Merged win32-branch

This commit is contained in:
Ron Pedde 2006-02-26 08:46:24 +00:00
parent bb894c5895
commit 9a133dcbdc
74 changed files with 12879 additions and 9204 deletions

View File

@ -6,6 +6,10 @@ body
color: #3C5C6B;
}
img
{ border: 0px;
}
table.main
{ border: 0px;

View File

@ -13,6 +13,9 @@ dnl AM_PROG_LEX
AC_CANONICAL_HOST
AC_CHECK_HEADERS([sys/wait.h])
AC_CHECK_FUNCS(strptime)
AC_CHECK_FUNCS(strtok_r)
AM_CONDITIONAL(COND_REND_OSX,false)
rend_posix=true

View File

@ -3,7 +3,7 @@
mv configure.in configure.in.mkdist
cat configure.in.mkdist | sed -e s/AM_INIT_AUTOMAKE.*$/AM_INIT_AUTOMAKE\(mt-daapd,cvs-`date +%Y%m%d`\)/ > configure.in
./reconf
./configure --with-id3tag=/sw
./configure --with-id3tag=/sw --enable-sqlite --enable-sqlite3
make dist
mv configure.in.mkdist configure.in

View File

@ -52,13 +52,17 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c \
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
os.h strptime.c strptime.h \
strtok_r.c strtok_r.h os-unix.h os-unix.c os.h \
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
$(MUSEPACKSRC) $(SQLITEDB) $(SQLITE3DB) $(SQLDB)
EXTRA_DIST = mDNS.c mDNSClientAPI.h mDNSDebug.h mDNSPosix.c \
mDNSUNP.c mDNSPlatformFunctions.h mDNSPosix.h mDNSUNP.h \
rend-howl.c rend-posix.c rend-osx.c scan-mpc.c \
strcasestr.h scan-ogg.c scan-flac.c db-sql.c db-sql.h \
scan-ogg.c scan-flac.c db-sql.c db-sql.h \
db-sql-sqlite2.h db-sql-sqlite2.c \
db-sql-sqlite3.h db-sql-sqlite3.c
db-sql-sqlite3.h db-sql-sqlite3.c \
w32-eventlog.c w32-eventlog.h w32-service.c w32-service.h \
os-win32.h os-win32.c win32.h

View File

@ -35,7 +35,6 @@
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <restart.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@ -45,11 +44,14 @@
#include <zlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include "configfile.h"
#include "db-generic.h"
#include "err.h"
#include "restart.h"
#include "xml-rpc.h"
#ifndef WITHOUT_MDNS
@ -71,6 +73,7 @@ static void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg
static void config_emit_user(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_readonly(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_version(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_debuglevel(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_system(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_flags(WS_CONNINFO *pwsc, void *value, char *arg);
static void config_emit_host(WS_CONNINFO *pwsc, void *value, char *arg);
@ -119,7 +122,7 @@ CONFIGELEMENT config_elements[] = {
{ 1,0,0,CONFIG_TYPE_STRING,"db_dir",(void*)&config.dbdir,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"db_type",(void*)&config.dbtype,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"db_parms",(void*)&config.dbparms,config_emit_string },
{ 1,0,0,CONFIG_TYPE_INT,"debuglevel",(void*)&err_debuglevel,config_emit_int },
{ 1,0,0,CONFIG_TYPE_INT,"debuglevel",(void*)NULL,config_emit_debuglevel },
{ 1,1,0,CONFIG_TYPE_STRING,"servername",(void*)&config.servername,config_emit_string },
{ 1,0,0,CONFIG_TYPE_INT,"rescan_interval",(void*)&config.rescan_interval,config_emit_int },
{ 1,0,0,CONFIG_TYPE_INT,"always_scan",(void*)&config.always_scan,config_emit_int },
@ -491,7 +494,7 @@ int config_read(char *file) {
*term_end='\0';
while(strlen(term_begin) && term_begin[strlen(term_begin)-1]==' ')
term_begin[strlen(term_begin)-1] == '\0';
term_begin[strlen(term_begin)-1] = '\0';
if(strlen(term_begin)) {
config.complist[currentterm++] = term_begin;
@ -866,8 +869,10 @@ void config_emit_int(WS_CONNINFO *pwsc, void *value, char *arg) {
* \param arg any args passwd with the meta command. Also unused
*/
void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
#ifndef WITHOUT_MDNS
int mdns_running;
char *html;
#endif
char buf[256];
int r_days, r_hours, r_mins, r_secs;
int scanning;
@ -919,7 +924,7 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
ws_writefd(pwsc,"<tr>\n");
ws_writefd(pwsc," <th>Uptime</th>\n");
r_secs=time(NULL)-config.stats.start_time;
r_secs=(int)(time(NULL)-config.stats.start_time);
r_days=r_secs/(3600 * 24);
r_secs -= ((3600 * 24) * r_days);
@ -1317,6 +1322,16 @@ void config_emit_version(WS_CONNINFO *pwsc, void *value, char *arg) {
ws_writefd(pwsc,"%s",VERSION);
}
/**
* implement the DEBUGLEVEL command
*
* @param pwsc web connection
* @param value the variable that was requested. Unused.
* @param arg any args passed with the meta command. Unused.
*/
void config_emit_debuglevel(WS_CONNINFO *pwsc, void *value, char *arg) {
ws_writefd(pwsc,"%d",err_getlevel());
}
/**
* implement the SYSTEM command.

View File

@ -59,7 +59,6 @@ typedef struct tag_config {
int process_m3u; /**< Should we process m3u files? */
int scan_type; /**< Method for finding playtime. see scan-mp3.c */
int compress; /**< Should we compress? */
int pid; /**< pid that will accept INT to terminate */
int latin1_tags; /**< interpret all tags as latin1 rather than utf8 */
char *adminpassword; /**< Password to web management pages */
char *readpassword; /**< iTunes password */
@ -83,7 +82,4 @@ typedef struct tag_config {
extern CONFIG config;
/* Forwards */
extern int drop_privs(char *user);
#endif /* _DAAPD_H_ */

View File

@ -231,12 +231,12 @@ DAAP_ITEMS taglist[] = {
{ 0x05, "aeSI", "com.apple.iTunes.itms-songid" },
{ 0x05, "aeSF", "com.apple.iTunes.itms-storefrontid" },
/* iTunes 5.0+ */
{ 0x01, "ascr", "daap.songcontentrating" },
{ 0x05, "f" "\x8d" "ch", "dmap.haschildcontainers" }, /* wtf - content codes says it's 1 */
/* iTunes 6.0.2+ */
{ 0x01, "aeHV", "com.apple.itunes.has-video" },
/* iTunes 5.0+ */
{ 0x01, "ascr", "daap.songcontentrating" },
{ 0x05, "f" "\x8d" "ch", "dmap.haschildcontainers" }, /* wtf - content codes says it's 1 */
/* iTunes 6.0.2+ */
{ 0x01, "aeHV", "com.apple.itunes.has-video" },
/* mt-daapd specific */
{ 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" },
@ -361,7 +361,7 @@ MetaField_t db_encode_meta(char *meta) {
if(0 == (end = strchr(start, ',')))
end = start + strlen(start);
len = end - start;
len = (int)(end - start);
if(*end != 0)
end++;
@ -789,11 +789,11 @@ int db_end_scan(void) {
}
void db_dispose_item(MP3FILE *pmp3) {
return db_current->dbs_dispose_item(pmp3);
db_current->dbs_dispose_item(pmp3);
}
void db_dispose_playlist(M3UFILE *pm3u) {
return db_current->dbs_dispose_playlist(pm3u);
db_current->dbs_dispose_playlist(pm3u);
}
int db_get_count(char **pe, int *count, CountType_t type) {
@ -899,7 +899,7 @@ int db_dmap_add_int(unsigned char *where, char *tag, int value) {
*/
int db_dmap_add_string(unsigned char *where, char *tag, char *value) {
int len=strlen(value);
int len=(int)strlen(value);
/* tag */
memcpy(where,tag,4);
@ -911,7 +911,7 @@ int db_dmap_add_string(unsigned char *where, char *tag, char *value) {
where[7]=len & 0xFF;
strncpy((char*)where+8,value,strlen(value));
return 8 + strlen(value);
return 8 + (int) strlen(value);
}
/**

View File

@ -41,7 +41,9 @@
#include <stdlib.h>
#include <string.h>
#include <sqlite.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "err.h"
#include "db-generic.h"

View File

@ -20,10 +20,10 @@
*/
/*
* This file handles sqlite2 databases. SQLite2 databases
* This file handles sqlite3 databases. SQLite3 databases
* should have a dsn of:
*
* sqlite2:/path/to/folder
* sqlite3:/path/to/folder
*
* The actual db will be appended to the passed path.
*/
@ -41,7 +41,10 @@
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <unistd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "err.h"
#include "db-generic.h"
@ -287,7 +290,7 @@ int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
}
for(idx=0; idx < cols; idx++) {
db_sqlite3_row[idx] = sqlite3_column_text(db_sqlite3_stmt,idx);
db_sqlite3_row[idx] = (char*) sqlite3_column_text(db_sqlite3_stmt,idx);
}
*pr = db_sqlite3_row;

View File

@ -238,9 +238,9 @@ int db_sql_parse_smart(char **pe, char **clause, char *phrase) {
if(!sp_parse(pt,phrase)) {
if(pe) *pe = strdup(sp_get_error(pt));
DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt));
sp_dispose(pt);
return FALSE;
} else {
@ -1202,7 +1202,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
case queryTypeBrowseAlbums:
case queryTypeBrowseGenres:
case queryTypeBrowseComposers:
return valarray[0] ? (8 + strlen(valarray[0])) : 0;
return valarray[0] ? (8 + (int) strlen(valarray[0])) : 0;
case queryTypePlaylists:
size = 8; /* mlit */
size += 12; /* mimc - you get it whether you want it or not */
@ -1213,10 +1213,10 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
size += 9; /* aeSP */
}
if(db_wantsmeta(pinfo->meta, metaItemName))
size += (8 + strlen(valarray[plTitle])); /* minm */
size += (8 + (int) strlen(valarray[plTitle])); /* minm */
if(valarray[plType] && (atoi(valarray[plType])==1) &&
db_wantsmeta(pinfo->meta, metaMPlaylistSpec))
size += (8 + strlen(valarray[plQuery])); /* MSPS */
size += (8 + (int) strlen(valarray[plQuery])); /* MSPS */
if(db_wantsmeta(pinfo->meta, metaMPlaylistType))
size += 9; /* MPTY */
return size;
@ -1244,13 +1244,13 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
size += 9;
if(ISSTR(valarray[13]) && db_wantsmeta(pinfo->meta, metaSongDataURL))
/* asul */
size += (8 + strlen(valarray[13]));
size += (8 + (int) strlen(valarray[13]));
if(ISSTR(valarray[5]) && db_wantsmeta(pinfo->meta, metaSongAlbum))
/* asal */
size += (8 + strlen(valarray[5]));
size += (8 + (int) strlen(valarray[5]));
if(ISSTR(valarray[4]) && db_wantsmeta(pinfo->meta, metaSongArtist))
/* asar */
size += (8 + strlen(valarray[4]));
size += (8 + (int) strlen(valarray[4]));
if(valarray[23] && atoi(valarray[23]) && db_wantsmeta(pinfo->meta, metaSongBPM))
/* asbt */
size += 10;
@ -1266,16 +1266,16 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
}
if(ISSTR(valarray[7]) && db_wantsmeta(pinfo->meta, metaSongComment))
/* ascm */
size += (8 + strlen(valarray[7]));
size += (8 + (int) strlen(valarray[7]));
if(valarray[24] && atoi(valarray[24]) && db_wantsmeta(pinfo->meta,metaSongCompilation))
/* asco */
size += 9;
if(ISSTR(valarray[9]) && db_wantsmeta(pinfo->meta, metaSongComposer))
/* ascp */
size += (8 + strlen(valarray[9]));
size += (8 + (int) strlen(valarray[9]));
if(ISSTR(valarray[12]) && db_wantsmeta(pinfo->meta, metaSongGrouping))
/* agrp */
size += (8 + strlen(valarray[12]));
size += (8 + (int) strlen(valarray[12]));
if(valarray[30] && atoi(valarray[30]) && db_wantsmeta(pinfo->meta, metaSongDateAdded))
/* asda */
size += 12;
@ -1290,7 +1290,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
/* asdn */
if(ISSTR(valarray[6]) && db_wantsmeta(pinfo->meta, metaSongGenre))
/* asgn */
size += (8 + strlen(valarray[6]));
size += (8 + (int) strlen(valarray[6]));
if(db_wantsmeta(pinfo->meta,metaItemId))
/* miid */
size += 12;
@ -1299,7 +1299,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
if(transcode) {
size += 11; /* 'wav' */
} else {
size += (8 + strlen(valarray[8]));
size += (8 + (int) strlen(valarray[8]));
}
}
if(ISSTR(valarray[29]) && db_wantsmeta(pinfo->meta,metaSongDescription)) {
@ -1307,12 +1307,12 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
if(transcode) {
size += 22; /* 'wav audio file' */
} else {
size += (8 + strlen(valarray[29]));
size += (8 + (int) strlen(valarray[29]));
}
}
if(ISSTR(valarray[3]) && db_wantsmeta(pinfo->meta,metaItemName))
/* minm */
size += (8 + strlen(valarray[3]));
size += (8 + (int) strlen(valarray[3]));
if(valarray[34] && atoi(valarray[34]) && db_wantsmeta(pinfo->meta,metaSongDisabled))
/* asdb */
size += 9;

View File

@ -27,10 +27,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <netinet/in.h>
#endif
#include "db-generic.h"
#include "configfile.h"
@ -40,9 +45,11 @@
#include "ssc.h"
#include "dynamic-art.h"
#include "restart.h"
#include "strtok_r.h"
#include "daapd.h"
#include "query.h"
/* Forwards */
static void dispatch_server_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
static void dispatch_login(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
@ -166,20 +173,30 @@ void daap_handler(WS_CONNINFO *pwsc) {
}
/* Start dispatching */
if(!strcasecmp(pqi->uri_sections[0],"server-info"))
return dispatch_server_info(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[0],"server-info")) {
dispatch_server_info(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[0],"content-codes"))
return dispatch_content_codes(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[0],"content-codes")) {
dispatch_content_codes(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[0],"login"))
return dispatch_login(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[0],"login")) {
dispatch_login(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[0],"update"))
return dispatch_update(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[0],"update")) {
dispatch_update(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[0],"logout"))
return dispatch_logout(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[0],"logout")) {
dispatch_logout(pwsc,pqi);
return;
}
/*
* /databases/id/items
@ -190,16 +207,21 @@ void daap_handler(WS_CONNINFO *pwsc) {
*/
if(!strcasecmp(pqi->uri_sections[0],"databases")) {
if(pqi->uri_count == 1) {
return dispatch_dbinfo(pwsc,pqi);
dispatch_dbinfo(pwsc,pqi);
return;
}
pqi->db_id=atoi(pqi->uri_sections[1]);
if(pqi->uri_count == 3) {
if(!strcasecmp(pqi->uri_sections[2],"items"))
if(!strcasecmp(pqi->uri_sections[2],"items")) {
/* /databases/id/items */
return dispatch_items(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[2],"containers"))
dispatch_items(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[2],"containers")) {
/* /databases/id/containers */
return dispatch_playlists(pwsc,pqi);
dispatch_playlists(pwsc,pqi);
return;
}
pwsc->close=1;
free(pqi);
@ -207,24 +229,35 @@ void daap_handler(WS_CONNINFO *pwsc) {
return;
}
if(pqi->uri_count == 4) {
if(!strcasecmp(pqi->uri_sections[2],"browse"))
if(!strcasecmp(pqi->uri_sections[2],"browse")) {
/* /databases/id/browse/something */
return dispatch_browse(pwsc,pqi);
if(!strcasecmp(pqi->uri_sections[2],"items"))
dispatch_browse(pwsc,pqi);
return;
}
if(!strcasecmp(pqi->uri_sections[2],"items")) {
/* /databases/id/items/id.mp3 */
return dispatch_stream(pwsc,pqi);
dispatch_stream(pwsc,pqi);
return;
}
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
(!strcasecmp(pqi->uri_sections[3],"add")))
/* /databases/id/containers/add */
return dispatch_addplaylist(pwsc,pqi);
(!strcasecmp(pqi->uri_sections[3],"add"))) {
/* /databases/id/containers/add */
dispatch_addplaylist(pwsc,pqi);
return;
}
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
(!strcasecmp(pqi->uri_sections[3],"del")))
/* /databases/id/containers/del */
return dispatch_deleteplaylist(pwsc,pqi);
(!strcasecmp(pqi->uri_sections[3],"del"))) {
/* /databases/id/containers/del */
dispatch_deleteplaylist(pwsc,pqi);
return;
}
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
(!strcasecmp(pqi->uri_sections[3],"edit")))
(!strcasecmp(pqi->uri_sections[3],"edit"))) {
/* /databases/id/contaienrs/edit */
return dispatch_editplaylist(pwsc,pqi);
dispatch_editplaylist(pwsc,pqi);
return;
}
pwsc->close=1;
free(pqi);
ws_returnerror(pwsc,404,"Page not found");
@ -234,13 +267,15 @@ void daap_handler(WS_CONNINFO *pwsc) {
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
(!strcasecmp(pqi->uri_sections[4],"items"))) {
pqi->playlist_id=atoi(pqi->uri_sections[3]);
return dispatch_playlistitems(pwsc,pqi);
dispatch_playlistitems(pwsc,pqi);
return;
}
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
(!strcasecmp(pqi->uri_sections[4],"del"))) {
/* /databases/id/containers/id/del */
pqi->playlist_id=atoi(pqi->uri_sections[3]);
return dispatch_deleteplaylistitems(pwsc,pqi);
dispatch_deleteplaylistitems(pwsc,pqi);
return;
}
}
if(pqi->uri_count == 6) {
@ -248,7 +283,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
(!strcasecmp(pqi->uri_sections[4],"items")) &&
(!strcasecmp(pqi->uri_sections[5],"add"))) {
pqi->playlist_id=atoi(pqi->uri_sections[3]);
return dispatch_addplaylistitems(pwsc,pqi);
dispatch_addplaylistitems(pwsc,pqi);
return;
}
}
}
@ -355,7 +391,7 @@ int dispatch_output_xml_write(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, unsigned char
while(current < (block + len)) {
block_done=1;
len_left=(block+len) - current;
len_left=(int)((block+len) - current);
if(len_left < 8) {
DPRINTF(E_FATAL,L_DAAP,"Badly formatted dmap block - frag size: %d",len_left);
}
@ -564,7 +600,7 @@ char *dispatch_xml_encode(char *original, int len) {
if(len) {
truelen=len;
} else {
truelen=strlen(original);
truelen=(int) strlen(original);
}
destsize = 6*truelen+1;
@ -1306,7 +1342,7 @@ void dispatch_dbinfo(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
int namelen;
int count;
namelen=strlen(config.servername);
namelen=(int) strlen(config.servername);
current += db_dmap_add_container(current,"avdb",105 + namelen);
current += db_dmap_add_int(current,"mstt",200); /* 12 */
@ -1363,7 +1399,7 @@ void dispatch_content_codes(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
dicurrent=taglist;
len=0;
while(dicurrent->type) {
len += (8 + 12 + 10 + 8 + strlen(dicurrent->description));
len += (8 + 12 + 10 + 8 + (int) strlen(dicurrent->description));
dicurrent++;
}
@ -1376,7 +1412,7 @@ void dispatch_content_codes(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
dicurrent=taglist;
while(dicurrent->type) {
current=mdcl;
len = 12 + 10 + 8 + strlen(dicurrent->description);
len = 12 + 10 + 8 + (int) strlen(dicurrent->description);
current += db_dmap_add_container(current,"mdcl",len);
current += db_dmap_add_string(current,"mcnm",dicurrent->tag); /* 12 */
current += db_dmap_add_string(current,"mcna",dicurrent->description); /* 8 + descr */
@ -1396,7 +1432,7 @@ void dispatch_server_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
int mpro = 2 << 16;
int apro = 3 << 16;
int actual_length=130 + strlen(config.servername);
int actual_length=130 + (int) strlen(config.servername);
if(actual_length > sizeof(server_info)) {
DPRINTF(E_FATAL,L_DAAP,"Server name too long.\n");
@ -1446,7 +1482,7 @@ void dispatch_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *container, char *
unsigned char *block, *current;
int len;
len = 12 + 8 + 8 + strlen(error);
len = 12 + 8 + 8 + (int) strlen(error);
block = (unsigned char *)malloc(len);
if(!block)

View File

@ -20,13 +20,19 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
@ -48,11 +54,11 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size);
This size is everything after the APIC text in this frame.
*/
/* APIC tag is made up from
APIC (4 bytes)
xxxx (4 bytes - Image size: raw + 16)
\0\0\0 (3 bytes)
image/jpeg (10 bytes)
\0\0\0 (3 bytes)
APIC (4 bytes)
xxxx (4 bytes - Image size: raw + 16)
\0\0\0 (3 bytes)
image/jpeg (10 bytes)
\0\0\0 (3 bytes)
Image-data
*/
#define id3v3_image_size(x) x + 14
@ -61,11 +67,11 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size);
/* This size is everything after the PIC in this frame
*/
/* PIC tag is made up of
PIC (3 bytes)
xxx (3 bytes - Image size: raw + 6)
\0 (1 byte)
JPG (3 bytes)
\0\0 (2 bytes)
PIC (3 bytes)
xxx (3 bytes - Image size: raw + 6)
\0 (1 byte)
JPG (3 bytes)
\0\0 (2 bytes)
Image-data
*/
@ -90,7 +96,7 @@ int da_get_image_fd(char *filename) {
strcpy(path_end+1,config.artfilename);
fd = open(buffer,O_RDONLY);
if(fd != -1)
DPRINTF(E_INF,L_ART,"Found image file %s (fd %d)\n",buffer,fd);
DPRINTF(E_INF,L_ART,"Found image file %s (fd %d)\n",buffer,fd);
return fd;
}
@ -105,20 +111,20 @@ int da_get_image_fd(char *filename) {
int *da_get_current_tag_info(int file_fd) {
unsigned char buffer[10];
int *tag_info;
tag_info = (int *) calloc(2,sizeof(int));
r_read(file_fd,buffer,10);
if (strncmp((char*)buffer,"ID3", 3) == 0 ) {
tag_info[0] = buffer[3];
tag_info[1] = ( buffer[6] << 21 ) + ( buffer[7] << 14 ) + ( buffer[8] << 7 ) + buffer[9];
return tag_info;
tag_info[0] = buffer[3];
tag_info[1] = ( buffer[6] << 21 ) + ( buffer[7] << 14 ) + ( buffer[8] << 7 ) + buffer[9];
return tag_info;
} else {
/* By default, we attach an id3v2.3 tag */
lseek(file_fd,0,SEEK_SET);
tag_info[0] = 2;
tag_info[1] = 0;
return tag_info;
/* By default, we attach an id3v2.3 tag */
lseek(file_fd,0,SEEK_SET);
tag_info[0] = 2;
tag_info[1] = 0;
return tag_info;
}
}
@ -143,14 +149,14 @@ int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset)
DPRINTF(E_INF,L_ART,"Image appears to be %ld bytes\n",img_size);
if(img_size < 1) {
r_close(img_fd);
return 0;
r_close(img_fd);
return 0;
}
if (offset > (img_size + 24) ) {
lseek(mp3_fd,(offset - img_size - 24),SEEK_SET);
r_close(img_fd);
return 0;
lseek(mp3_fd,(offset - img_size - 24),SEEK_SET);
r_close(img_fd);
return 0;
}
tag_info = da_get_current_tag_info(mp3_fd);
@ -159,35 +165,35 @@ int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset)
DPRINTF(E_INF,L_ART,"Current tag size is %d bytes\n",tag_size);
if (tag_info[0] == 3) {
r_write(out_fd,"ID3\x03\0\0",6);
tag_size += id3v3_tag_size(img_size);
r_write(out_fd,"ID3\x03\0\0",6);
tag_size += id3v3_tag_size(img_size);
} else {
r_write(out_fd,"ID3\x02\0\0",6);
tag_size += id3v2_tag_size(img_size);
r_write(out_fd,"ID3\x02\0\0",6);
tag_size += id3v2_tag_size(img_size);
}
buffer[3] = tag_size & 0x7F;
buffer[2] = ( tag_size & 0x3F80 ) >> 7;
buffer[1] = ( tag_size & 0x1FC000 ) >> 14;
buffer[0] = ( tag_size & 0xFE00000 ) >> 21;
r_write(out_fd,buffer,4);
if (tag_info[0] == 3) {
r_write(out_fd,"APIC\0",5);
img_size = id3v3_image_size(img_size);
r_write(out_fd,"APIC\0",5);
img_size = id3v3_image_size(img_size);
} else {
r_write(out_fd,"PIC",3);
img_size = id3v2_image_size(img_size);
r_write(out_fd,"PIC",3);
img_size = id3v2_image_size(img_size);
}
buffer[0] = ( img_size & 0xFF0000 ) >> 16;
buffer[1] = ( img_size & 0xFF00 ) >> 8;
buffer[2] = ( img_size & 0xFF );
buffer[0] = ( (int) img_size & 0xFF0000 ) >> 16;
buffer[1] = ( (int) img_size & 0xFF00 ) >> 8;
buffer[2] = ( (int) img_size & 0xFF );
r_write(out_fd,buffer,3);
if (tag_info[0] == 3) {
r_write(out_fd,"\0\0\0image/jpeg\0\0\0",16);
r_write(out_fd,"\0\0\0image/jpeg\0\0\0",16);
} else {
r_write(out_fd,"\0JPG\x00\0",6);
r_write(out_fd,"\0JPG\x00\0",6);
}
lseek(img_fd,0,SEEK_SET);
copyfile(img_fd,out_fd);
@ -226,41 +232,41 @@ off_t da_aac_rewrite_stco_atom(off_t extra_size, int out_fd, FILE *aac_fp,
/* Drill down to the 'stco' atom which contains offsets to chunks in
the 'mdat' section. These offsets need to be readjusted. */
atom_offset = scan_aac_drilltoatom(aac_fp, "moov:trak:mdia:minf:stbl:stco",
&atom_length);
&atom_length);
if (atom_offset != -1) {
/* Skip flags */
fseek(aac_fp, 4, SEEK_CUR);
/* Skip flags */
fseek(aac_fp, 4, SEEK_CUR);
old_pos = last_pos;
cur_pos = ftell(aac_fp);
old_pos = last_pos;
cur_pos = ftell(aac_fp);
/* Copy from last point to this point. */
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
/* Copy from last point to this point. */
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
/* Read number of entries */
fread(buffer, 1, 4, aac_fp);
r_write(out_fd, buffer, 4);
/* Read number of entries */
fread(buffer, 1, 4, aac_fp);
r_write(out_fd, buffer, 4);
num_entries = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
num_entries = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
DPRINTF(E_DBG, L_ART,"Readjusting %d 'stco' table offsets.\n", num_entries);
/* PENDING: Error check on num_entries? */
for (i = 0; i < num_entries; i++) {
fread(buffer, 1, 4, aac_fp);
offset_entry = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
/* Adjust chunk offset. */
offset_entry += extra_size;
buffer[3] = offset_entry & 0xFF;
buffer[2] = (offset_entry >> 8) & 0xFF;
buffer[1] = (offset_entry >> 16) & 0xFF;
buffer[0] = (offset_entry >> 24) & 0xFF;
r_write(out_fd, buffer, 4);
offset_entry = 0;
}
return ftell(aac_fp);
DPRINTF(E_DBG, L_ART,"Readjusting %d 'stco' table offsets.\n", num_entries);
/* PENDING: Error check on num_entries? */
for (i = 0; i < (int)num_entries; i++) {
fread(buffer, 1, 4, aac_fp);
offset_entry = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
/* Adjust chunk offset. */
offset_entry += extra_size;
buffer[3] = offset_entry & 0xFF;
buffer[2] = (offset_entry >> 8) & 0xFF;
buffer[1] = (offset_entry >> 16) & 0xFF;
buffer[0] = (offset_entry >> 24) & 0xFF;
r_write(out_fd, buffer, 4);
offset_entry = 0;
}
return ftell(aac_fp);
} else {
DPRINTF(E_LOG, L_ART,"No 'stco' atom found.\n");
DPRINTF(E_LOG, L_ART,"No 'stco' atom found.\n");
}
return last_pos;
}
@ -285,17 +291,17 @@ off_t da_aac_insert_covr_atom(off_t extra_size, int out_fd, FILE *aac_fp,
/* Figure out image file type since this needs to be encoded in the atom. */
cp = strrchr(config.artfilename, '.');
if (cp) {
if (!strcasecmp(cp, ".jpeg") || !strcasecmp(cp, ".jpg")) {
img_type_flag = 0x0d;
}
else if (!strcasecmp(cp, ".png")) {
img_type_flag = 0x0e;
} else {
DPRINTF(E_LOG,L_ART, "Image type '%s' not supported.\n", cp);
return 0;
}
if (!strcasecmp(cp, ".jpeg") || !strcasecmp(cp, ".jpg")) {
img_type_flag = 0x0d;
}
else if (!strcasecmp(cp, ".png")) {
img_type_flag = 0x0e;
} else {
DPRINTF(E_LOG,L_ART, "Image type '%s' not supported.\n", cp);
return 0;
}
} else {
DPRINTF(E_LOG, L_ART, "No file extension for image file.\n");
DPRINTF(E_LOG, L_ART, "No file extension for image file.\n");
}
aac_fd = fileno(aac_fp);
@ -305,119 +311,119 @@ off_t da_aac_insert_covr_atom(off_t extra_size, int out_fd, FILE *aac_fp,
atom_offset = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length);
if (atom_offset != -1) {
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "udta", &atom_length);
if (atom_offset != -1) {
old_pos = last_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found udta atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "udta", &atom_length);
if (atom_offset != -1) {
old_pos = last_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found udta atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
cur_pos += 4;
fseek(aac_fp, 8, SEEK_CUR);
cur_pos += 4;
fseek(aac_fp, 8, SEEK_CUR);
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "meta", &atom_length);
if (atom_offset != -1) {
old_pos = cur_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found meta atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "meta", &atom_length);
if (atom_offset != -1) {
old_pos = cur_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found meta atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
cur_pos += 4;
fseek(aac_fp, 12, SEEK_CUR); /* "meta" atom hack. */
cur_pos += 4;
fseek(aac_fp, 12, SEEK_CUR); /* "meta" atom hack. */
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "ilst", &atom_length);
if (atom_offset != -1) {
old_pos = cur_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found ilst atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "ilst", &atom_length);
if (atom_offset != -1) {
old_pos = cur_pos;
cur_pos = ftell(aac_fp) - 8;
DPRINTF(E_INF,L_ART,"Found ilst atom at %ld.\n", cur_pos);
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
old_pos = cur_pos + 4;
cur_pos += atom_length;
old_pos = cur_pos + 4;
cur_pos += atom_length;
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out new length */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Copy all 'ilst' children (all the MP4 'tags'). We will append
at the end. */
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
cur_pos = ftell(aac_fp);
/* Copy all 'ilst' children (all the MP4 'tags'). We will append
at the end. */
fseek(aac_fp, old_pos, SEEK_SET);
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
cur_pos = ftell(aac_fp);
/* Write out 'covr' atom */
atom_length = extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out 'covr' atom */
atom_length = extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
r_write(out_fd, "covr", 4);
r_write(out_fd, "covr", 4);
/* Write out 'data' atom */
atom_length = extra_size - 8;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out 'data' atom */
atom_length = extra_size - 8;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
r_write(out_fd, "data", 4);
r_write(out_fd, "data", 4);
/* Write out 'data' flags */
buffer[3] = img_type_flag;
buffer[2] = 0;
buffer[1] = 0;
buffer[0] = 0;
r_write(out_fd, buffer, 4);
/* Write out 'data' flags */
buffer[3] = img_type_flag;
buffer[2] = 0;
buffer[1] = 0;
buffer[0] = 0;
r_write(out_fd, buffer, 4);
/* Reserved? Zero in any case. */
buffer[3] = 0;
buffer[2] = 0;
buffer[1] = 0;
buffer[0] = 0;
/* Reserved? Zero in any case. */
buffer[3] = 0;
buffer[2] = 0;
buffer[1] = 0;
buffer[0] = 0;
r_write(out_fd, buffer, 4);
r_write(out_fd, buffer, 4);
/* Now ready for the image stream. Copy it over. */
lseek(img_fd,0,SEEK_SET);
copyfile(img_fd,out_fd);
last_pos = cur_pos;
} else {
DPRINTF(E_LOG, L_ART,"No 'ilst' atom found.\n");
}
} else {
DPRINTF(E_LOG,L_ART, "No 'meta' atom found.\n");
}
} else {
DPRINTF(E_LOG,L_ART, "No 'udta' atom found.\n");
}
/* Now ready for the image stream. Copy it over. */
lseek(img_fd,0,SEEK_SET);
copyfile(img_fd,out_fd);
last_pos = cur_pos;
} else {
DPRINTF(E_LOG, L_ART,"No 'ilst' atom found.\n");
}
} else {
DPRINTF(E_LOG,L_ART, "No 'meta' atom found.\n");
}
} else {
DPRINTF(E_LOG,L_ART, "No 'udta' atom found.\n");
}
} else {
DPRINTF(E_LOG,L_ART, "No 'moov' atom found.\n");
DPRINTF(E_LOG,L_ART, "No 'moov' atom found.\n");
}
/* Seek to position right after 'udta' atom. Let main() stream out the
@ -456,8 +462,8 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
/* PENDING: We can be stricter here by checking the shortest header between
PNG and JPG and using that length. */
if (img_size < 1) {
r_close(img_fd);
return 0;
r_close(img_fd);
return 0;
}
/* Include extra bytes for 'covr' atom length (4) and type (4) and its
@ -471,21 +477,21 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
aac_fp = fdopen(dup(aac_fd), "r");
stco_atom_pos = scan_aac_drilltoatom(aac_fp,
"moov:trak:mdia:minf:stbl:stco",
&atom_length);
"moov:trak:mdia:minf:stbl:stco",
&atom_length);
ilst_atom_pos = scan_aac_drilltoatom(aac_fp, "moov:udta:meta:ilst",
&atom_length);
&atom_length);
last_pos = scan_aac_drilltoatom(aac_fp, "mdat", &atom_length);
if (last_pos != -1) {
if (offset >= last_pos) {
/* Offset is in the actual music data so don't bother processing
meta data. */
return 0;
}
if (offset >= last_pos) {
/* Offset is in the actual music data so don't bother processing
meta data. */
return 0;
}
} else {
DPRINTF(E_LOG,L_ART, "No 'mdat' atom.\n");
return 0;
DPRINTF(E_LOG,L_ART, "No 'mdat' atom.\n");
return 0;
}
rewind(aac_fp);
@ -493,32 +499,32 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
/* Re-adjust length of 'moov' atom. */
last_pos = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length);
if (last_pos != -1) {
/* Copy everything from up to this atom */
rewind(aac_fp);
fcopyblock(aac_fp, out_fd, last_pos);
/* Copy everything from up to this atom */
rewind(aac_fp);
fcopyblock(aac_fp, out_fd, last_pos);
/* Write out new length. */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
/* Write out new length. */
atom_length += extra_size;
buffer[3] = atom_length & 0xFF;
buffer[2] = ( atom_length >> 8 ) & 0xFF;
buffer[1] = ( atom_length >> 16 ) & 0xFF;
buffer[0] = ( atom_length >> 24 ) & 0xFF;
r_write(out_fd, buffer, 4);
last_pos += 4;
last_pos += 4;
} else {
DPRINTF(E_LOG,L_ART, "Could not find 'moov' atom.\n");
return 0;
DPRINTF(E_LOG,L_ART, "Could not find 'moov' atom.\n");
return 0;
}
if (stco_atom_pos < ilst_atom_pos) {
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
file_size, img_fd);
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
file_size, img_fd);
} else {
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
file_size, img_fd);
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
file_size, img_fd);
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
}
/* Seek to position right after last atom. Let main() stream out the rest. */
@ -537,20 +543,20 @@ int copyblock(int fromfd, int tofd, size_t size) {
int blocksize = BLKSIZE;
int bytesleft;
while (totalbytes < size) {
bytesleft = size - totalbytes;
if (bytesleft < BLKSIZE) {
blocksize = bytesleft;
} else {
blocksize = BLKSIZE;
}
if ((bytesread = r_read(fromfd, buf, blocksize)) < 0)
return -1;
if (bytesread == 0)
return totalbytes;
if (r_write(tofd, buf, bytesread) < 0)
return -1;
totalbytes += bytesread;
while (totalbytes < (int) size) {
bytesleft = (int) (size - totalbytes);
if (bytesleft < BLKSIZE) {
blocksize = bytesleft;
} else {
blocksize = BLKSIZE;
}
if ((bytesread = r_read(fromfd, buf, blocksize)) < 0)
return -1;
if (bytesread == 0)
return totalbytes;
if (r_write(tofd, buf, bytesread) < 0)
return -1;
totalbytes += bytesread;
}
return totalbytes;
}
@ -562,23 +568,23 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size) {
int blocksize = BLKSIZE;
int bytesleft;
while (totalbytes < size) {
bytesleft = size - totalbytes;
if (bytesleft < BLKSIZE) {
blocksize = bytesleft;
} else {
blocksize = BLKSIZE;
}
if ((bytesread = fread(buf, 1, blocksize, fromfp)) < blocksize) {
if (ferror(fromfp))
return -1;
}
if (r_write(tofd, buf, bytesread) < 0)
return -1;
while (totalbytes < (int) size) {
bytesleft = (int)(size - totalbytes);
if (bytesleft < BLKSIZE) {
blocksize = bytesleft;
} else {
blocksize = BLKSIZE;
}
if ((bytesread = (int) fread(buf, 1, blocksize, fromfp)) < blocksize) {
if (ferror(fromfp))
return -1;
}
if (r_write(tofd, buf, bytesread) < 0)
return -1;
if (feof(fromfp))
return 0;
totalbytes += bytesread;
if (feof(fromfp))
return 0;
totalbytes += bytesread;
}
return totalbytes;
}

302
src/err.c
View File

@ -39,18 +39,11 @@
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
/* don't want to redefine malloc -- if doing memory debugging,
* this is the only file that *shouldn't* be redefining malloc and
* friends. Hence the define.
*/
#define __IN_ERR__
#include "err.h"
#include "os.h"
int err_debuglevel=0; /**< current debuglevel, set from command line with -d */
static int err_debuglevel=0; /**< current debuglevel, set from command line with -d */
static int err_logdestination=LOGDEST_STDERR; /**< current log destination */
static FILE *err_file=NULL; /**< if logging to file, the handle of that file */
static pthread_mutex_t err_mutex=PTHREAD_MUTEX_INITIALIZER; /**< for serializing log messages */
@ -62,33 +55,16 @@ static char *err_categorylist[] = {
"playlist","art","daap","main","rend","xml","parse",NULL
};
#ifdef DEBUG_MEMORY
/**
* Nodes for a linked list of in-use memory. Any malloc/strdup/etc
* calls get a new node of this type added to the #err_leak list.
*/
typedef struct tag_err_leak {
void *ptr;
char *file;
int line;
int size;
struct tag_err_leak *next;
} ERR_LEAK;
/** head of linked list of in-use memory */
ERR_LEAK err_leak = { NULL, NULL, 0, 0, NULL };
#endif
/*
* Forwards
*/
static int err_lock_mutex(void);
static int err_unlock_mutex(void);
static int _err_lock(void);
static int _err_unlock(void);
/**
* Write a printf-style formatted message to the log destination.
* This can be stderr, syslog, or a logfile, as determined by
* This can be stderr, syslog/eventviewer, or a logfile, as determined by
* err_setdest(). Note that this function should not be directly
* used, rather it should be used via the #DPRINTF macro.
*
@ -105,81 +81,92 @@ void err_log(int level, unsigned int cat, char *fmt, ...)
time_t tt_now;
if(level) {
if(level > err_debuglevel)
return;
if(level > err_debuglevel)
return;
if(!(cat & err_debugmask))
return;
if(!(cat & err_debugmask))
return;
} /* we'll *always* process a log level 0 */
va_start(ap, fmt);
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
va_end(ap);
err_lock_mutex(); /* atomic file writes */
_err_lock(); /* atomic file writes */
if((!level) && (err_logdestination != LOGDEST_STDERR)) {
fprintf(stderr,"%s",errbuf);
fprintf(stderr,"Aborting\n");
fflush(stderr); /* shouldn't have to do this? */
fprintf(stderr,"%s",errbuf);
fprintf(stderr,"Aborting\n");
fflush(stderr); /* shouldn't have to do this? */
}
switch(err_logdestination) {
case LOGDEST_LOGFILE:
tt_now=time(NULL);
localtime_r(&tt_now,&tm_now);
strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %T",&tm_now);
fprintf(err_file,"%s: %s",timebuf,errbuf);
if(!level) fprintf(err_file,"%s: Aborting\n",timebuf);
fflush(err_file);
break;
tt_now=time(NULL);
localtime_r(&tt_now,&tm_now);
strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %T",&tm_now);
fprintf(err_file,"%s: %s",timebuf,errbuf);
if(!level) fprintf(err_file,"%s: Aborting\n",timebuf);
fflush(err_file);
break;
case LOGDEST_STDERR:
fprintf(stderr, "%s",errbuf);
if(!level) fprintf(stderr,"Aborting\n");
if(!level) fprintf(stderr,"Aborting\n");
break;
case LOGDEST_SYSLOG:
syslog(LOG_NOTICE, "%s", errbuf);
if(!level) syslog(LOG_INFO, "Aborting\n");
os_syslog(level,errbuf);
if(!level) os_syslog(0, "Fatal error... Aborting\n");
break;
}
err_unlock_mutex();
_err_unlock();
if(!level) {
exit(EXIT_FAILURE);
exit(EXIT_FAILURE); /* this should go to an OS-specific exit routine */
}
}
/*
* simple get/set interface to debuglevel to avoid global
*/
void err_setlevel(int level) {
err_debuglevel = level;
}
int err_getlevel(void) {
return err_debuglevel;
}
/**
* Sets the log destination. (stderr, syslog, or logfile)
*
* \param app appname (used only for syslog destination)
* \param destination where to log to \ref log_dests "as defined in err.h"
*/
void err_setdest(char *app, int destination) {
void err_setdest(char *cvalue, int destination) {
if(err_logdestination == destination)
return;
return;
switch(err_logdestination) {
case LOGDEST_SYSLOG:
closelog();
break;
os_closesyslog();
break;
case LOGDEST_LOGFILE:
fclose(err_file);
break;
fclose(err_file);
break;
}
switch(destination) {
case LOGDEST_LOGFILE:
err_file=fopen(app,"a");
if(err_file==NULL) {
fprintf(stderr,"Error opening %s: %s\n",app,strerror(errno));
exit(EXIT_FAILURE);
}
break;
err_file=fopen(cvalue,"a");
if(err_file==NULL) {
fprintf(stderr,"Error opening %s: %s\n",cvalue,strerror(errno));
exit(EXIT_FAILURE);
}
break;
case LOGDEST_SYSLOG:
openlog(app,LOG_PID,LOG_DAEMON);
break;
os_opensyslog(); // (app,LOG_PID,LOG_DAEMON);
break;
}
err_logdestination=destination;
@ -200,26 +187,26 @@ extern int err_setdebugmask(char *list) {
str=list;
while(1) {
token=strtok_r(str,",",&last);
str=NULL;
token=strtok_r(str,",",&last);
str=NULL;
if(token) {
rack=1;
index=0;
while((err_categorylist[index]) &&
(strcasecmp(err_categorylist[index],token))) {
rack <<= 1;
index++;
}
if(token) {
rack=1;
index=0;
while((err_categorylist[index]) &&
(strcasecmp(err_categorylist[index],token))) {
rack <<= 1;
index++;
}
if(!err_categorylist[index]) {
DPRINTF(E_LOG,L_MISC,"Unknown module: %s\n",token);
return 1;
} else {
DPRINTF(E_DBG,L_MISC,"Adding module %s to debug list (0x%08x)\n",token,rack);
err_debugmask |= rack;
}
} else break; /* !token */
if(!err_categorylist[index]) {
DPRINTF(E_LOG,L_MISC,"Unknown module: %s\n",token);
return 1;
} else {
DPRINTF(E_DBG,L_MISC,"Adding module %s to debug list (0x%08x)\n",token,rack);
err_debugmask |= rack;
}
} else break; /* !token */
}
DPRINTF(E_INF,L_MISC,"Debug mask is 0x%08x\n",err_debugmask);
@ -234,12 +221,12 @@ extern int err_setdebugmask(char *list) {
*
* \returns 0 on success, otherwise -1 with errno set
*/
int err_lock_mutex(void) {
int _err_lock(void) {
int err;
if((err=pthread_mutex_lock(&err_mutex))) {
errno=err;
return -1;
errno=err;
return -1;
}
return 0;
@ -250,155 +237,14 @@ int err_lock_mutex(void) {
*
* \returns 0 on success, otherwise -1 with errno set
*/
int err_unlock_mutex(void) {
int _err_unlock(void) {
int err;
if((err=pthread_mutex_unlock(&err_mutex))) {
errno=err;
return -1;
errno=err;
return -1;
}
return 0;
}
#ifdef DEBUG_MEMORY
/**
* Let the leak detector know about a chunk of memory
* that needs to be freed, but came from an external library.
* Example: gdbm functions. Note that this should only
* be called via the #MEMNOTIFY macro.
*
* \param file filled in from the #MEMNOTIFY macro with __FILE__
* \param line filled in from the #MEMNOTIFY macro with __LINE__
* \param ptr ptr to block of memory which must be freed
*/
void err_notify(char *file, int line, void *ptr) {
ERR_LEAK *pnew;
if(!ptr)
return;
pnew=(ERR_LEAK*)malloc(sizeof(ERR_LEAK));
if(!pnew)
DPRINTF(E_FATAL,L_MISC,"Error: cannot allocate leak struct\n");
if(err_lock_mutex())
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
pnew->file=file;
pnew->line=line;
pnew->size=0;
pnew->ptr=ptr;
pnew->next=err_leak.next;
err_leak.next=pnew;
err_unlock_mutex();
}
/**
* malloc wrapper for leak checking. This never gets
* called directly, only via malloc.
*
* \param file filled in via macro with __FILE__
* \param line filled in via macro with __LINE__
* \param size size of block to allocate
*/
void *err_malloc(char *file, int line, size_t size) {
ERR_LEAK *pnew;
pnew=(ERR_LEAK*)malloc(sizeof(ERR_LEAK));
if(!pnew)
DPRINTF(E_FATAL,L_MISC,"Error: cannot allocate leak struct\n");
if(err_lock_mutex())
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
pnew->file=file;
pnew->line=line;
pnew->size=size;
pnew->ptr=malloc(size);
pnew->next=err_leak.next;
err_leak.next=pnew;
err_unlock_mutex();
return pnew->ptr;
}
/**
* Memory check wrapper for strdup. This should not
* be called directly
*
* \param file filled in via macro with __FILE__
* \param line filled in via macro with __LINE__
* \param str str to strdup
*/
char *err_strdup(char *file, int line, const char *str) {
void *pnew;
pnew=err_malloc(file,line,strlen(str) + 1);
if(!pnew)
DPRINTF(E_FATAL,L_MISC,"Cannot malloc enough space for strdup\n");
memcpy(pnew,str,strlen(str)+1);
return pnew;
}
/**
* Memory checking wrapper for free. This should not be
* called direclty.
*
* \param file filled in by macro with __FILE__
* \param line filled in by macro with __LINE__
* \param ptr block of memory to free
*/
void err_free(char *file, int line, void *ptr) {
ERR_LEAK *current,*last;
if(err_lock_mutex())
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
last=&err_leak;
current=last->next;
while((current) && (current->ptr != ptr)) {
last=current;
current=current->next;
}
if(!current) {
DPRINTF(E_FATAL,L_MISC,"Attempt to free unallocated memory: %s, %d\n",file,line);
} else {
free(current->ptr);
last->next=current->next;
free(current);
}
err_unlock_mutex();
}
/**
* Dumps the list of in-use memory. This walks the linked
* list created by the malloc and strdup wrappers, and dumps
* them to stdout.
*/
void err_leakcheck(void) {
ERR_LEAK *current;
if(err_lock_mutex())
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
current=err_leak.next;
while(current) {
printf("%s: %d - %d bytes at %p\n",current->file, current->line, current->size,
current->ptr);
current=current->next;
}
err_unlock_mutex();
}
#endif

View File

@ -30,7 +30,7 @@
/** @anchor log_dests */
#define LOGDEST_STDERR 0 /**< Log to stderr */
#define LOGDEST_SYSLOG 1 /**< Log to syslog */
#define LOGDEST_SYSLOG 1 /**< Log to syslog/eventviewer */
#define LOGDEST_LOGFILE 2 /**< Log to logfile */
/** @anchor log_levels */
@ -63,40 +63,15 @@
# define FALSE 0
#endif
extern int err_debuglevel;
extern void err_log(int level, unsigned int cat, char *fmt, ...);
extern void err_setdest(char *app, int destination);
extern void err_setdest(char *cvalue, int destination);
extern void err_setlevel(int level);
extern int err_getlevel(void);
extern int err_setdebugmask(char *list);
/**
* Print a debugging or log message
*/
#ifdef DEBUG
# define DPRINTF(level, cat, fmt, arg...) \
{ err_log(level,cat,"%s, %d: ",__FILE__,__LINE__); err_log(level,cat,fmt,##arg); }
#else
# define DPRINTF(level, cat, fmt, arg...) \
{ err_log(level,cat,fmt,##arg); }
#endif
#ifdef DEBUG_MEMORY
# ifndef __IN_ERR__
# define malloc(x) err_malloc(__FILE__,__LINE__,x)
# define strdup(x) err_strdup(__FILE__,__LINE__,x)
# define free(x) err_free(__FILE__,__LINE__,x)
# endif /* __IN_ERR__ */
#define DPRINTF err_log
# define MEMNOTIFY(x) err_notify(__FILE__,__LINE__,x)
extern void *err_malloc(char *file, int line, size_t size);
extern char *err_strdup(char *file, int line, const char *str);
extern void err_free(char *file, int line, void *ptr);
extern void err_notify(char *file, int line, void *ptr);
extern void err_leakcheck(void);
#else
/**
* Notify the leak checking system of externally allocated memory.
*/
# define MEMNOTIFY(x)
#endif /* DEBUG_MEMORY */
#endif /* __ERR_H__ */

1265
src/getopt.c Normal file

File diff suppressed because it is too large Load Diff

181
src/getopt.h Normal file
View File

@ -0,0 +1,181 @@
/* Declarations for getopt.
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
/* If __GNU_LIBRARY__ is not already defined, either we are being used
standalone, or this is the first header included in the source file.
If we are being used with glibc, we need to include <features.h>, but
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
not defined, include <ctype.h>, which will pull in <features.h> for us
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
doesn't flood the namespace with stuff the way some other headers do.) */
#if !defined __GNU_LIBRARY__
# include <ctype.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
#ifndef __need_getopt
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
# if (defined __STDC__ && __STDC__) || defined __cplusplus
const char *name;
# else
char *name;
# endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, `optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in `optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU `getopt'.
The argument `--' causes premature termination of argument
scanning, explicitly telling `getopt' that there are no more
options.
If OPTS begins with `--', then non-option arguments are treated as
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
# else /* not __GNU_LIBRARY__ */
extern int getopt ();
# endif /* __GNU_LIBRARY__ */
# ifndef __need_getopt
extern int getopt_long (int ___argc, char *const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only (int ___argc, char *const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int ___argc, char *const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */

9932
src/mDNS.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,12 @@
Change History (most recent first):
$Log$
Revision 1.4 2006/02/26 08:46:24 rpedde
Merged win32-branch
Revision 1.3.2.1 2006/02/26 08:28:35 rpedde
unix fixes from win32 port
Revision 1.3 2005/07/21 03:40:07 rpedde
Crank up mdns debug messages
@ -78,41 +84,41 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
#define IS_A_PRINTF_STYLE_FUNCTION(F,A)
#endif
#ifdef __cplusplus
extern "C" {
#ifdef __cplusplus
extern "C" {
#endif
#if MDNS_DEBUGMSGS
#define debugf debugf_
extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
#else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
#if( defined( __GNUC__ ) )
#define debugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define debugf( ... )
#else
#define debugf 1 ? ((void)0) : (void)
#endif
#if( defined( __GNUC__ ) )
#define debugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define debugf( ... )
#else
#define debugf 1 ? ((void)0) : (void)
#endif
#endif
#if MDNS_DEBUGMSGS > 1
#define verbosedebugf verbosedebugf_
extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
#else
#if( defined( __GNUC__ ) )
#define verbosedebugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define verbosedebugf( ... )
#else
#define verbosedebugf 1 ? ((void)0) : (void)
#endif
#if( defined( __GNUC__ ) )
#define verbosedebugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define verbosedebugf( ... )
#else
#define verbosedebugf 1 ? ((void)0) : (void)
#endif
#endif
// LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
#ifdef __cplusplus
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,12 @@
Change History (most recent first):
$Log$
Revision 1.3 2006/02/26 08:46:24 rpedde
Merged win32-branch
Revision 1.2.4.1 2006/02/26 08:28:35 rpedde
unix fixes from win32 port
Revision 1.2 2005/01/10 01:07:01 rpedde
Synchronize mDNS to Apples 58.8 drop
@ -74,10 +80,10 @@ First checkin
extern int gMDNSPlatformPosixVerboseLevel;
struct mDNS_PlatformSupport_struct
{
{
// No additional data required for Posix at this time
long dummy[1]; // Some compilers don't like empty structures
};
long dummy[1]; // Some compilers don't like empty structures
};
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// See comment in implementation.

View File

@ -23,6 +23,12 @@
Change History (most recent first):
$Log$
Revision 1.6 2006/02/26 08:46:24 rpedde
Merged win32-branch
Revision 1.5.2.1 2006/02/26 08:28:35 rpedde
unix fixes from win32 port
Revision 1.5 2005/09/23 05:26:52 rpedde
commit the iTunes 5 fixes
@ -161,23 +167,23 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
ifr = (struct ifreq *) ptr;
len = GET_SA_LEN(ifr->ifr_addr);
len = GET_SA_LEN(ifr->ifr_addr);
/* This is completely whacked, and I really need to
* find out why this is the case, but I need to
* release a 0.2.2, and as the next stable won't
* have the apple mDNS included, I guess it's a
* small price to pay.
*/
/* This is completely whacked, and I really need to
* find out why this is the case, but I need to
* release a 0.2.2, and as the next stable won't
* have the apple mDNS included, I guess it's a
* small price to pay.
*/
#ifdef FREEBSD
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
// ptr += sizeof(*ifr);
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
// ptr += sizeof(*ifr);
#else
ptr += sizeof(struct ifreq); /* for next one in buffer */
ptr += sizeof(struct ifreq); /* for next one in buffer */
#endif
DPRINTF(E_DBG,L_REND,"intf %d name=%s AF=%d, flags=%08x\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family,ifr->ifr_flags);
DPRINTF(E_DBG,L_REND,"intf %d name=%s AF=%d, flags=%08x\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family,ifr->ifr_flags);
if (ifr->ifr_addr.sa_family != family)
continue; /* ignore if not desired address family */
@ -267,7 +273,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
/* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
/* We need to strip that out */
if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
sinptr6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
sinptr6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
}
break;
@ -364,7 +370,7 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
/* include recvfrom_flags2 */
#ifndef CMSG_FIRSTHDR
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
*flagsp = 0; /* pass back results */
return(n);
#else
@ -431,15 +437,15 @@ struct in_pktinfo
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_PKTINFO) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(*sin6);
sin6->sin6_addr = ip6_info->ipi6_addr;
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
sin6->sin6_port = 0;
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
continue;
}
#endif

View File

@ -20,7 +20,7 @@
*/
/**
* \file main.c
* @file main.c
*
* Driver for mt-daapd, including the main() function. This
* is responsible for kicking off the initial mp3 scan, starting
@ -31,21 +31,19 @@
* It also contains the daap handling callback for the webserver.
* This should almost certainly be somewhere else, and is in
* desparate need of refactoring, but somehow continues to be in
* this file.
*
* \todo Refactor daap_handler()
* this files.
*/
/** \mainpage mt-daapd
* \section about_section About
/** @mainpage mt-daapd
* @section about_section About
*
* This is mt-daapd, an attempt to create an iTunes server for
* linux and other POSIXish systems. Maybe even Windows with cygwin,
* eventually.
*
* You might check these locations for more info:
* - <a href="http://www.mt-daapd.org">Home page</a>
* - <a href="http://sf.net/projects/mt-daapd">Project page on SourceForge</a>
* - <a href="http://mt-daapd.sf.net">Home page</a>
*
*/
@ -55,29 +53,36 @@
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <pthread.h>
#include <pwd.h>
#include <restart.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include "configfile.h"
#include "dispatch.h"
#include "err.h"
#include "mp3-scanner.h"
#include "webserver.h"
#include "restart.h"
#include "ssc.h"
#include "dynamic-art.h"
#include "db-generic.h"
#include "os.h"
#ifdef HAVE_GETOPT_H
# include "getopt.h"
#endif
#ifndef WITHOUT_MDNS
# include "rend.h"
@ -94,16 +99,6 @@
#endif
#endif
/** Where to dump the pidfile */
#ifndef PIDFILE
#define PIDFILE "/var/run/mt-daapd.pid"
#endif
/** You say po-tay-to, I say po-tat-o */
#ifndef SIGCLD
# define SIGCLD SIGCHLD
#endif
/** Seconds to sleep before checking for a shutdown or reload */
#define MAIN_SLEEP_INTERVAL 2
@ -120,61 +115,7 @@ CONFIG config; /**< Main configuration structure, as read from configfile */
/*
* Forwards
*/
static int daemon_start(void);
static void usage(char *program);
static void *signal_handler(void *arg);
static int start_signal_handler(pthread_t *handler_tid);
/**
* Fork and exit. Stolen pretty much straight from Stevens.
*/
int daemon_start(void) {
int childpid, fd;
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
// Fork and exit
if ((childpid = fork()) < 0) {
fprintf(stderr, "Can't fork!\n");
return -1;
} else if (childpid > 0)
exit(0);
#ifdef SETPGRP_VOID
setpgrp();
#else
setpgrp(0,0);
#endif
#ifdef TIOCNOTTY
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(fd, TIOCNOTTY, (char *) NULL);
close(fd);
}
#endif
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
/*
for (fd = 0; fd < FOPEN_MAX; fd++)
close(fd);
*/
errno = 0;
chdir("/");
umask(0);
return 0;
}
/**
* Print usage information to stdout
@ -198,133 +139,6 @@ void usage(char *program) {
printf("\n\n");
}
/**
* Drop privs. This allows mt-daapd to run as a non-privileged user.
* Hopefully this will limit the damage it could do if exploited
* remotely. Note that only the user need be specified. GID
* is set to the primary group of the user.
*
* \param user user to run as (or UID)
*/
int drop_privs(char *user) {
int err;
struct passwd *pw=NULL;
/* drop privs */
if(getuid() == (uid_t)0) {
if(atoi(user)) {
pw=getpwuid((uid_t)atoi(user)); /* doh! */
} else {
pw=getpwnam(config.runas);
}
if(pw) {
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
err=errno;
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
user,pw->pw_gid, pw->pw_uid);
errno=err;
return -1;
}
} else {
err=errno;
fprintf(stderr,"Couldn't lookup user %s\n",user);
errno=err;
return -1;
}
}
return 0;
}
/**
* Wait for signals and flag the main process. This is
* a thread handler for the signal processing thread. It
* does absolutely nothing except wait for signals. The rest
* of the threads are running with signals blocked, so this thread
* is guaranteed to catch all the signals. It sets flags in
* the config structure that the main thread looks for. Specifically,
* the stop flag (from an INT signal), and the reload flag (from HUP).
* \param arg NULL, but required of a thread procedure
*/
void *signal_handler(void *arg) {
sigset_t intmask;
int sig;
int status;
config.stop=0;
config.reload=0;
config.pid=getpid();
DPRINTF(E_WARN,L_MAIN,"Signal handler started\n");
while(!config.stop) {
if((sigemptyset(&intmask) == -1) ||
(sigaddset(&intmask, SIGCLD) == -1) ||
(sigaddset(&intmask, SIGINT) == -1) ||
(sigaddset(&intmask, SIGHUP) == -1) ||
(sigwait(&intmask, &sig) == -1)) {
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals. Aborting\n");
} else {
/* process the signal */
switch(sig) {
case SIGCLD:
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
while (wait3(&status, WNOHANG, NULL) > 0) {
}
break;
case SIGINT:
DPRINTF(E_LOG,L_MAIN,"Got INT signal. Notifying daap server.\n");
config.stop=1;
return NULL;
break;
case SIGHUP:
DPRINTF(E_LOG,L_MAIN,"Got HUP signal. Notifying daap server.\n");
config.reload=1;
break;
default:
DPRINTF(E_LOG,L_MAIN,"What am I doing here?\n");
break;
}
}
}
return NULL;
}
/**
* Block signals, then start the signal handler. The
* signal handler started by spawning a new thread on
* signal_handler().
*
* \returns 0 on success, -1 on failure with errno set
*/
int start_signal_handler(pthread_t *handler_tid) {
int error;
sigset_t set;
if((sigemptyset(&set) == -1) ||
(sigaddset(&set,SIGINT) == -1) ||
(sigaddset(&set,SIGHUP) == -1) ||
(sigaddset(&set,SIGCLD) == -1) ||
(sigprocmask(SIG_BLOCK, &set, NULL) == -1)) {
DPRINTF(E_LOG,L_MAIN,"Error setting signal set\n");
return -1;
}
if((error=pthread_create(handler_tid, NULL, signal_handler, NULL))) {
errno=error;
DPRINTF(E_LOG,L_MAIN,"Error creating signal_handler thread\n");
return -1;
}
/* we'll not detach this... let's join it */
//pthread_detach(handler_tid);
return 0;
}
/**
* Kick off the daap server and wait for events.
*
@ -346,7 +160,6 @@ int start_signal_handler(pthread_t *handler_tid) {
int main(int argc, char *argv[]) {
int option;
char *configfile=DEFAULT_CONFIGFILE;
char *pidfile=PIDFILE;
WSCONFIG ws_config;
int foreground=0;
int reload=0;
@ -356,20 +169,17 @@ int main(int argc, char *argv[]) {
int old_song_count, song_count;
int force_non_root=0;
int skip_initial=0;
pthread_t signal_tid;
int pid_fd;
FILE *pid_fp=NULL;
int err;
char *perr;
config.use_mdns=1;
err_debuglevel=1;
err_setlevel(1);
while((option=getopt(argc,argv,"D:d:c:P:mfrys")) != -1) {
while((option=getopt(argc,argv,"D:d:c:P:mfrysiu")) != -1) {
switch(option) {
case 'd':
err_debuglevel=atoi(optarg);
err_setlevel(atoi(optarg));
break;
case 'D':
if(err_setdebugmask(optarg)) {
@ -389,10 +199,11 @@ int main(int argc, char *argv[]) {
config.use_mdns=0;
break;
#ifndef WIN32
case 'P':
pidfile=optarg;
os_set_pidfile(optarg);
break;
#endif
case 'r':
reload=1;
break;
@ -405,6 +216,18 @@ int main(int argc, char *argv[]) {
force_non_root=1;
break;
#ifdef WIN32
case 'i':
os_register();
exit(EXIT_SUCCESS);
break;
case 'u':
os_unregister();
exit(EXIT_SUCCESS);
break;
#endif
default:
usage(argv[0]);
exit(EXIT_FAILURE);
@ -420,7 +243,7 @@ int main(int argc, char *argv[]) {
/* read the configfile, if specified, otherwise
* try defaults */
config.stats.start_time=start_time=time(NULL);
config.stats.start_time=start_time=(int)time(NULL);
config.stop=0;
if(config_read(configfile)) {
@ -428,7 +251,7 @@ int main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
DPRINTF(E_LOG,L_MAIN,"Starting with debuglevel %d\n",err_debuglevel);
DPRINTF(E_LOG,L_MAIN,"Starting with debuglevel %d\n",err_getlevel());
if(!foreground) {
if(config.logfile) {
@ -447,48 +270,14 @@ int main(int argc, char *argv[]) {
}
#endif
/* open the pidfile, so it can be written once we detach */
if((!foreground) && (!force_non_root)) {
if(-1 == (pid_fd = open(pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644)))
DPRINTF(E_FATAL,L_MAIN,"Error opening pidfile (%s): %s\n",pidfile,strerror(errno));
if(0 == (pid_fp = fdopen(pid_fd, "w")))
DPRINTF(E_FATAL,L_MAIN,"fdopen: %s\n",strerror(errno));
/* just to be on the safe side... */
config.pid=0;
daemon_start();
}
// Drop privs here
if(drop_privs(config.runas)) {
DPRINTF(E_FATAL,L_MAIN,"Error in drop_privs: %s\n",strerror(errno));
}
/* block signals and set up the signal handling thread */
DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n");
if(start_signal_handler(&signal_tid)) {
DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno));
}
if(pid_fp) {
/* wait to for config.pid to be set by the signal handler */
while(!config.pid) {
sleep(1);
}
fprintf(pid_fp,"%d\n",config.pid);
fclose(pid_fp);
if(!os_init(foreground)) {
DPRINTF(E_LOG,L_MAIN,"Could not initialize server\n");
os_deinit();
exit(EXIT_FAILURE);
}
/* this will require that the db be readable by the runas user */
if(config.dbtype) {
err=db_open(&perr,config.dbtype,config.dbparms);
} else {
err=db_open(&perr,NULL,config.dbdir);
}
err=db_open(&perr,config.dbtype,config.dbparms);
if(err)
DPRINTF(E_FATAL,L_MAIN|L_DB,"Error in db_open: %s\n",perr);
@ -535,7 +324,7 @@ int main(int argc, char *argv[]) {
}
#endif
end_time=time(NULL);
end_time=(int) time(NULL);
db_get_song_count(NULL,&song_count);
DPRINTF(E_LOG,L_MAIN,"Scanned %d songs in %d seconds\n",song_count,
@ -553,7 +342,7 @@ int main(int argc, char *argv[]) {
if(config.reload) {
old_song_count = song_count;
start_time=time(NULL);
start_time=(int) time(NULL);
DPRINTF(E_LOG,L_MAIN|L_DB|L_SCAN,"Rescanning database\n");
if(scan_init(config.mp3dir)) {
@ -581,11 +370,6 @@ int main(int argc, char *argv[]) {
#endif
DPRINTF(E_LOG,L_MAIN,"Stopping signal handler\n");
if(!pthread_kill(signal_tid,SIGINT)) {
pthread_join(signal_tid,NULL);
}
/* Got to find a cleaner way to stop the web server.
* Closing the fd of the socking accepting doesn't necessarily
* cause the accept to fail on some libcs.
@ -599,15 +383,11 @@ int main(int argc, char *argv[]) {
DPRINTF(E_LOG,L_MAIN|L_DB,"Closing database\n");
db_deinit();
#ifdef DEBUG_MEMORY
fprintf(stderr,"Leaked memory:\n");
err_leakcheck();
#endif
DPRINTF(E_LOG,L_MAIN,"Done!\n");
err_setdest(NULL,LOGDEST_STDERR);
os_deinit();
return EXIT_SUCCESS;
}

View File

@ -27,7 +27,7 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "config.h"
#endif
#define _POSIX_PTHREAD_SEMANTICS
@ -36,19 +36,21 @@
#include <fcntl.h>
#include <id3tag.h>
#include <limits.h>
#include <restart.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <netinet/in.h> /* htons and friends */
#include <sys/stat.h>
#include <dirent.h> /* why here? For osx 10.2, of course! */
#endif
#include <sys/stat.h>
#include "daapd.h"
#include "db-generic.h"
#include "err.h"
#include "mp3-scanner.h"
#include "restart.h"
#include "ssc.h"
#ifndef HAVE_STRCASESTR
@ -136,7 +138,7 @@ static TAGHANDLER taghandlers[] = {
{ "wma", scan_get_wmainfo, "wma", "wma", "WMA audio file" },
{ "url", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
{ "pls", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
{ "m4v", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" },
{ "m4v", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" },
#ifdef OGGVORBIS
{ "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" },
#endif
@ -345,7 +347,7 @@ int scan_path(char *path) {
} else if (((ext = strrchr(pde->d_name, '.')) != NULL) &&
(strcasestr(config.extensions, ext))) {
/* only scan if it's been changed, or empty db */
modified_time=sb.st_mtime;
modified_time=(int) sb.st_mtime;
pmp3=db_fetch_path(NULL,mp3_path,0);
if((!pmp3) || (pmp3->db_timestamp < modified_time) ||
@ -411,9 +413,9 @@ int scan_static_playlist(char *path) {
}
if(pm3u) {
DPRINTF(E_DBG,L_SCAN,"Playlist needs updated\n");
/* welcome to texas, y'all */
db_delete_playlist(NULL,pm3u->id);
DPRINTF(E_DBG,L_SCAN,"Playlist needs updated\n");
/* welcome to texas, y'all */
db_delete_playlist(NULL,pm3u->id);
}
fd=open(path,O_RDONLY);
@ -423,7 +425,7 @@ int scan_static_playlist(char *path) {
DPRINTF(E_LOG,L_SCAN,"Error adding m3u %s: %s\n",path,perr);
free(perr);
db_dispose_playlist(pm3u);
close(fd);
close(fd);
return FALSE;
}
/* now get the *real* base_path */
@ -483,13 +485,15 @@ int scan_static_playlist(char *path) {
void scan_music_file(char *path, struct dirent *pde,
struct stat *psb, int is_compdir) {
MP3FILE mp3file;
char tmp_path[PATH_MAX];
char mp3_path[PATH_MAX];
char *current=NULL;
char *type;
TAGHANDLER *ptaghandler;
char fdescr[50];
snprintf(mp3_path,sizeof(mp3_path),"%s/%s",path,pde->d_name);
snprintf(tmp_path,sizeof(mp3_path),"%s/%s",path,pde->d_name);
realpath(tmp_path,mp3_path);
/* we found an mp3 file */
DPRINTF(E_INF,L_SCAN,"Found music file: %s\n",pde->d_name);
@ -537,10 +541,10 @@ void scan_music_file(char *path, struct dirent *pde,
My thinking is to use time created, but what is that? Best
guess would be earliest of st_mtime and st_ctime...
*/
mp3file.time_added=psb->st_mtime;
mp3file.time_added=(int) psb->st_mtime;
if(psb->st_ctime < mp3file.time_added)
mp3file.time_added=psb->st_ctime;
mp3file.time_modified=psb->st_mtime;
mp3file.time_added=(int) psb->st_ctime;
mp3file.time_modified=(int) psb->st_mtime;
DPRINTF(E_DBG,L_SCAN," Date Added: %d\n",mp3file.time_added);
@ -648,9 +652,9 @@ void make_composite_tags(MP3FILE *song) {
if(!song->artist && (song->orchestra || song->conductor)) {
if(song->orchestra)
len += strlen(song->orchestra);
len += (int) strlen(song->orchestra);
if(song->conductor)
len += strlen(song->conductor);
len += (int) strlen(song->conductor);
len += 3;

View File

@ -64,9 +64,9 @@ typedef struct tag_mp3file {
int got_id3;
unsigned int id;
char *description; /* long file type */
char *description; /* long file type */
char *codectype; /* song.codectype */
int item_kind; /* song or movie */
int item_kind; /* song or movie */
int data_kind; /* dmap.datakind (asdk) */
int force_update;
int sample_count;

379
src/os-unix.c Normal file
View File

@ -0,0 +1,379 @@
/*
* $Id$
* Abstracts os interface
*
* Copyright (c) 2006 Ron Pedde (rpedde@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pthread.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_WAIT
# include <sys/wait.h>
#endif
#include <sys/time.h>
#include <sys/resource.h>
#include "err.h"
#include "daapd.h"
#include "os-unix.h"
/** You say po-tay-to, I say po-tat-o */
#ifndef SIGCLD
# define SIGCLD SIGCHLD
#endif
/** Where to dump the pidfile */
#ifndef PIDFILE
#define PIDFILE "/var/run/mt-daapd.pid"
#endif
/* Forwards */
static int _os_daemon_start(void);
static void *_os_signal_handler(void *arg);
static int _os_start_signal_handler(pthread_t *handler_tid);
static volatile int _os_signal_pid;
/* Globals */
pthread_t _os_signal_tid;
char *_os_pidfile = PIDFILE;
/**
* this initializes the platform... sets up signal handlers, forks to the
* background, etc
*
* @param foreground whether to run in fg or fork to bg
* @returns TRUE on success, FALSE otherwise
*/
int os_init(int foreground) {
int pid_fd;
FILE *pid_fp=NULL;
/* open the pidfile, so it can be written once we detach */
if(!foreground) {
if(-1 == (pid_fd = open(_os_pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644))) {
DPRINTF(E_LOG,L_MAIN,"Error opening pidfile (%s): %s\n",
_os_pidfile,strerror(errno));
} else {
if(0 == (pid_fp = fdopen(pid_fd, "w")))
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
}
/* just to be on the safe side... */
_os_signal_pid=0;
_os_daemon_start();
}
// Drop privs here
if(os_drop_privs(config.runas)) {
DPRINTF(E_FATAL,L_MAIN,"Error in drop_privs: %s\n",strerror(errno));
}
/* block signals and set up the signal handling thread */
DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n");
if(_os_start_signal_handler(&_os_signal_tid)) {
DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno));
}
if(pid_fp) {
/* wait to for config.pid to be set by the signal handler */
while(!_os_signal_pid) {
sleep(1);
}
fprintf(pid_fp,"%d\n",_os_signal_pid);
fclose(pid_fp);
}
return TRUE;
}
/**
* do any deinitialization necessary for the platform
*/
void os_deinit(void) {
DPRINTF(E_LOG,L_MAIN,"Stopping signal handler\n");
if(!pthread_kill(_os_signal_tid,SIGINT)) {
pthread_join(_os_signal_tid,NULL);
}
}
/**
* start syslogging
*
* @returns TRUE on success, FALSE otherwise
*/
int os_opensyslog(void) {
openlog(PACKAGE,LOG_PID,LOG_DAEMON);
return TRUE;
}
/**
* stop syslogging
*
* @returns TRUE on success, FALSE otherwise
*/
int os_closesyslog(void) {
closelog();
return TRUE;
}
/**
* log a syslog message
*
* @param level log level (1-9: 1=fatal, 9=debug)
* @param msg message to log to the syslog
* @returns TRUE on success, FALSE otherwise
*/
int os_syslog(int level, char *msg) {
int priority;
switch(level) {
case 0:
case 1:
priority = LOG_ALERT;
break;
case 2:
case 3:
case 4:
priority = LOG_NOTICE;
break;
case 5:
case 6:
case 7:
case 8:
priority = LOG_INFO;
break;
case 9:
default:
priority = LOG_DEBUG;
break;
}
syslog(priority,"%s",msg);
return TRUE;
}
/**
* Fork and exit. Stolen pretty much straight from Stevens.
*
* @returns 0 on success, -1 with errno set on error
*/
int _os_daemon_start(void) {
int childpid, fd;
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
// Fork and exit
if ((childpid = fork()) < 0) {
fprintf(stderr, "Can't fork!\n");
return -1;
} else if (childpid > 0)
exit(0);
#ifdef SETPGRP_VOID
setpgrp();
#else
setpgrp(0,0);
#endif
#ifdef TIOCNOTTY
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(fd, TIOCNOTTY, (char *) NULL);
close(fd);
}
#endif
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
/*
for (fd = 0; fd < FOPEN_MAX; fd++)
close(fd);
*/
errno = 0;
chdir("/");
umask(0);
return 0;
}
/**
* Drop privs. This allows mt-daapd to run as a non-privileged user.
* Hopefully this will limit the damage it could do if exploited
* remotely. Note that only the user need be specified. GID
* is set to the primary group of the user.
*
* \param user user to run as (or UID)
*/
int os_drop_privs(char *user) {
int err;
struct passwd *pw=NULL;
/* drop privs */
if(getuid() == (uid_t)0) {
if(atoi(user)) {
pw=getpwuid((uid_t)atoi(user)); /* doh! */
} else {
pw=getpwnam(config.runas);
}
if(pw) {
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
err=errno;
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
user,pw->pw_gid, pw->pw_uid);
errno=err;
return -1;
}
} else {
err=errno;
fprintf(stderr,"Couldn't lookup user %s\n",user);
errno=err;
return -1;
}
}
return 0;
}
/**
* Wait for signals and flag the main process. This is
* a thread handler for the signal processing thread. It
* does absolutely nothing except wait for signals. The rest
* of the threads are running with signals blocked, so this thread
* is guaranteed to catch all the signals. It sets flags in
* the config structure that the main thread looks for. Specifically,
* the stop flag (from an INT signal), and the reload flag (from HUP).
* \param arg NULL, but required of a thread procedure
*/
void *_os_signal_handler(void *arg) {
sigset_t intmask;
int sig;
int status;
config.stop=0;
config.reload=0;
_os_signal_pid=getpid();
DPRINTF(E_WARN,L_MAIN,"Signal handler started\n");
while(!config.stop) {
if((sigemptyset(&intmask) == -1) ||
(sigaddset(&intmask, SIGCLD) == -1) ||
(sigaddset(&intmask, SIGINT) == -1) ||
(sigaddset(&intmask, SIGHUP) == -1) ||
(sigwait(&intmask, &sig) == -1)) {
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals. Aborting\n");
} else {
/* process the signal */
switch(sig) {
case SIGCLD:
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
while (wait3(&status, WNOHANG, NULL) > 0) {
}
break;
case SIGINT:
DPRINTF(E_LOG,L_MAIN,"Got INT signal. Notifying daap server.\n");
config.stop=1;
return NULL;
break;
case SIGHUP:
DPRINTF(E_LOG,L_MAIN,"Got HUP signal. Notifying daap server.\n");
config.reload=1;
break;
default:
DPRINTF(E_LOG,L_MAIN,"What am I doing here?\n");
break;
}
}
}
return NULL;
}
/**
* Block signals, then start the signal handler. The
* signal handler started by spawning a new thread on
* signal_handler().
*
* \returns 0 on success, -1 on failure with errno set
*/
int _os_start_signal_handler(pthread_t *handler_tid) {
int error;
sigset_t set;
if((sigemptyset(&set) == -1) ||
(sigaddset(&set,SIGINT) == -1) ||
(sigaddset(&set,SIGHUP) == -1) ||
(sigaddset(&set,SIGCLD) == -1) ||
(sigprocmask(SIG_BLOCK, &set, NULL) == -1)) {
DPRINTF(E_LOG,L_MAIN,"Error setting signal set\n");
return -1;
}
if((error=pthread_create(handler_tid, NULL, _os_signal_handler, NULL))) {
errno=error;
DPRINTF(E_LOG,L_MAIN,"Error creating signal_handler thread\n");
return -1;
}
/* we'll not detach this... let's join it */
//pthread_detach(handler_tid);
return 0;
}
/**
* set the pidfile to a non-default value
*
* @param file file to use as pidfile
*/
void os_set_pidfile(char *file) {
_os_pidfile = file;
}

15
src/os-unix.h Normal file
View File

@ -0,0 +1,15 @@
/*
* $Id$
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
*
*/
#ifndef _OS_UNIX_H_
#define _OS_UNIX_H_
/* unix-specific functions */
extern int os_drop_privs(char *user);
void os_set_pidfile(char *file);
#endif

645
src/os-win32.c Normal file
View File

@ -0,0 +1,645 @@
/* $Id$
*
*/
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "daapd.h"
#include "win32.h"
#include "err.h"
#include "os-win32.h"
#include "w32-eventlog.h"
#include "w32-service.h"
/* Globals */
static WSADATA w32_wsadata;
static os_serviceflag = 0;
static pthread_t os_service_tid;
static os_initialized=0;
static pthread_mutex_t os_mutex=PTHREAD_MUTEX_INITIALIZER;
/* Forwards */
static void _os_socket_startup(void);
static void _os_socket_shutdown(void);
static int _os_sock_to_fd(SOCKET sock);
static void _os_lock(void);
static void _os_unlock(void);
static BOOL WINAPI _os_cancelhandler(DWORD dwCtrlType);
extern int gettimeout(struct timeval end,struct timeval *timeoutp);
#define OSFI_OPEN 1
#define OSFI_SHUTDOWN 2
#define NOTSOCK (fd < MAXDESC)
#define REALSOCK (file_info[fd - MAXDESC].sock)
#define SOCKSTATE (file_info[fd - MAXDESC].state)
#define MAXBACKLOG 5
typedef struct tag_osfileinfo {
SOCKET sock;
int state;
} OSFILEINFO;
/* Globals */
OSFILEINFO file_info[MAXDESC];
char os_config_file[_MAX_PATH];
/* "official" os interface functions */
/**
* initialize the os-specific stuff. this would include
* backgrounding (or starting as service), setting up
* signal handlers (or ctrl-c handlers), etc
*
* @param background whether or not to start in background (service)
* @returns TRUE on success, FALSE otherwise
*/
int os_init(int foreground) {
int err;
_os_socket_startup();
if(!os_initialized) {
_os_lock();
if(!os_initialized) {
memset((void*)&file_info,0,sizeof(file_info));
}
os_initialized=1;
_os_unlock();
}
if(!foreground) {
/* startup as service */
os_serviceflag = 1;
if((err=pthread_create(&os_service_tid,NULL,service_startup,NULL))) {
DPRINTF(E_LOG,L_MISC,"Could not spawn thread: %s\n",strerror(err));
return FALSE;
}
} else {
/* let's set a ctrl-c handler! */
SetConsoleCtrlHandler(_os_cancelhandler,TRUE);
}
return TRUE;
}
/**
* shutdown the system-specific stuff started in os_init.
*/
void os_deinit(void) {
_os_socket_shutdown();
if(os_serviceflag) {
/* then we need to stop the service */
SetConsoleCtrlHandler(_os_cancelhandler,FALSE);
service_shutdown(0);
}
}
/**
* open the syslog (eventlog)
*/
int os_opensyslog(void) {
return elog_init();
}
/**
* close the syslog (eventlog)
*/
int os_closesyslog(void) {
return elog_deinit();
}
/**
* write a message to the syslog
*
* @param level what level of message (1-10)
* @param msg message to write
* @return TRUE on success, FALSE otherwise
*/
int os_syslog(int level, char *msg) {
return elog_message(level, msg);
}
int os_register(void) {
service_register();
elog_register();
return TRUE;
}
int os_unregister(void) {
service_unregister();
elog_unregister();
return TRUE;
}
static BOOL WINAPI _os_cancelhandler(DWORD dwCtrlType) {
DPRINTF(E_LOG,L_MISC,"Shutting down with a console event\n");
config.stop = 1;
return TRUE;
}
int _os_sock_to_fd(SOCKET sock) {
int fd;
if(sock == INVALID_SOCKET)
return -1;
DPRINTF(E_SPAM,L_MISC,"Converting socket to fd\n");
/* I was doing strange osfhandle stuff here, but it seemed
* to be leaking file handles, and I don't really know what
* it was doing. Thanks, Microsoft. Anyway, since I'm handling
* reads, writes, opens and closes, I might just as well hand out
* FAKE fds and swap them out to SOCKETS when I need to. No
* more fd leaks. Problem solved.
*/
/*
fd=_open_osfhandle(sock,O_RDWR|O_BINARY);
// fd=_open_osfhandle(sock,0);
if(fd > 0) {
file_info[fd].flags = OSFI_SOCKET | OSFI_OPEN;
file_info[fd].sock=sock;
} else {
DPRINTF(E_LOG,L_MISC,"Could not fd for socket osfhandle\n");
}
*/
_os_lock();
fd=0;
while((fd < MAXDESC) && (file_info[fd].state)) {
fd++;
}
if(fd == MAXDESC) {
_os_unlock();
DPRINTF(E_FATAL,L_MISC,"Out of pseudo file handles. See ya\n");
}
DPRINTF(E_SPAM,L_MISC,"Returning fd %d\n",fd + MAXDESC);
file_info[fd].sock = sock;
file_info[fd].state = OSFI_OPEN;
_os_unlock();
return fd + MAXDESC;
}
int os_acceptsocket(int fd, char *hostn, int hostnsize) {
socklen_t len = sizeof(struct sockaddr);
struct sockaddr_in netclient;
SOCKET retval;
DPRINTF(E_SPAM,L_MISC,"Accepting socket %d -- %d\n",fd,REALSOCK);
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN)) {
DPRINTF(E_LOG,L_MISC,"Bad socket passed to accept\n");
return -1;
}
while (((retval =
accept(REALSOCK,(struct sockaddr *)(&netclient), &len)) == SOCKET_ERROR) &&
(WSAGetLastError() == WSAEINTR));
if ((retval == INVALID_SOCKET) || (hostn == NULL) || (hostnsize <= 0)) {
DPRINTF(E_LOG,L_MISC,"Error accepting...\n");
return _os_sock_to_fd(retval);
}
strncpy(hostn,inet_ntoa(netclient.sin_addr),hostnsize);
return _os_sock_to_fd(retval);
}
int os_waitfdtimed(int fd, struct timeval end) {
fd_set readset;
int retval;
struct timeval timeout;
SOCKET sock;
DPRINTF(E_SPAM,L_MISC,"Timed wait on fd %d\n");
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN))
return -1;
sock = REALSOCK;
/*
if ((fd < 0) || (fd >= FD_SETSIZE)) {
errno = EINVAL;
return -1;
}
*/
FD_ZERO(&readset);
FD_SET(sock, &readset);
if (gettimeout(end, &timeout) == -1)
return -1;
while (((retval = select(1, &readset, NULL, NULL, NULL)) == SOCKET_ERROR)
&& (WSAGetLastError() == WSAEINTR)) {
if (gettimeout(end, &timeout) == -1)
return -1;
FD_ZERO(&readset);
FD_SET(fd, &readset);
}
if (retval == 0) {
errno = ETIME;
return -1;
}
if (retval == -1)
return -1;
DPRINTF(E_SPAM,L_MISC,"Timed wait successful\n");
return 0;
}
/* from the gnu c library */
char *os_strsep(char **stringp, const char *delim) {
char *begin, *end;
begin = *stringp;
if (begin == NULL)
return NULL;
/* A frequent case is when the delimiter string contains only one
character. Here we don't need to call the expensive `strpbrk'
function and instead work using `strchr'. */
if (delim[0] == '\0' || delim[1] == '\0') {
char ch = delim[0];
if (ch == '\0') {
end = NULL;
} else {
if (*begin == ch)
end = begin;
else if (*begin == '\0')
end = NULL;
else
end = strchr (begin + 1, ch);
}
} else {
/* Find the end of the token. */
end = strpbrk (begin, delim);
}
if (end) {
/* Terminate the token and set *STRINGP past NUL character. */
*end++ = '\0';
*stringp = end;
} else {
/* No more delimiters; this is the last token. */
*stringp = NULL;
}
return begin;
}
int os_opensocket(unsigned short port) {
int error;
struct sockaddr_in server;
SOCKET sock;
int true = 1;
int fd;
DPRINTF(E_SPAM,L_MISC,"Opening socket\n");
/* make sure the file_info struct is initialized */
if(!os_initialized) {
_os_lock();
if(!os_initialized) {
memset((void*)&file_info,0,sizeof(file_info));
os_initialized=1;
}
_os_unlock();
}
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return -1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&true,
sizeof(true)) == SOCKET_ERROR) {
error = WSAGetLastError();
while ((closesocket(sock) == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
errno = EINVAL; /* windows errnos suck */
return -1;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons((short)port);
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) ||
(listen(sock, MAXBACKLOG) == -1)) {
error = errno;
while ((closesocket(sock) == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
errno = EINVAL; /* should be addrinuse or somethign */
return -1;
}
fd=_os_sock_to_fd(sock);
DPRINTF(E_SPAM,L_MISC,"created socket %d\n",fd);
return fd;
}
int os_write(int fd, void *buffer, unsigned int count) {
int retval;
if(NOTSOCK) {
retval = _write(fd,buffer,count);
} else {
if(SOCKSTATE != OSFI_OPEN) {
DPRINTF(E_LOG,L_MISC,"Write to socket with status: %d\n",
file_info[fd-MAXDESC].state);
return -1;
}
retval=send(REALSOCK,buffer,count,0);
}
return retval;
}
int os_read(int fd,void *buffer,unsigned int count) {
int retval;
DPRINTF(E_SPAM,L_MISC,"Reading %d bytes from %d\n",count,fd);
if(NOTSOCK) {
retval = _read(fd,buffer,count);
} else {
if(SOCKSTATE != OSFI_OPEN) {
DPRINTF(E_LOG,L_MISC,"Read to socket with status: %d\n",
file_info[fd-MAXDESC].state);
return -1;
}
retval=recv(REALSOCK,buffer,count,0);
DPRINTF(E_SPAM,L_MISC,"Actually returning %d\n",retval);
}
return retval;
}
int os_shutdown(int fd, int how) {
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN))
return -1;
SOCKSTATE = OSFI_SHUTDOWN;
shutdown(REALSOCK,how);
return 0;
}
/* FIXME: mode */
int os_open(const char *filename, int oflag) {
int fd;
fd = _open(filename, oflag | O_BINARY);
return fd;
}
int os_close(int fd) {
if(NOTSOCK) {
_close(fd);
} else { /* socket */
if(SOCKSTATE == OSFI_OPEN) {
os_shutdown(fd,SHUT_RDWR);
}
if(SOCKSTATE == OSFI_SHUTDOWN) {
closesocket(REALSOCK);
SOCKSTATE = 0;
}
}
return 0;
}
/**
* get uid of current user. this is really stubbed, as it's only used
* as a check during startup (it fails normally if you run non-root, as it means
* that it can't drop privs, can't write pidfile, etc)
*/
int os_getuid(void) {
return 0;
}
/**
* this is now pretty close to a true realpath implementation
*/
char *os_realpath(const char *pathname, char *resolved_path) {
char *ptr;
if(!_fullpath(resolved_path,pathname,PATH_MAX)) {
DPRINTF(E_FATAL,L_MISC,"Could not realpath %s\n",pathname);
}
ptr = resolved_path;
while(*ptr) {
*ptr = tolower(*ptr);
if(*ptr == '/')
*ptr = '\\';
ptr++;
}
return &resolved_path[0];
}
int os_gettimeofday (struct timeval *tv, struct timezone* tz) {
union {
long long ns100; /*time since 1 Jan 1601 in 100ns units */
FILETIME ft;
} now;
GetSystemTimeAsFileTime (&now.ft);
tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
if(tz) {
tz->tz_minuteswest = _timezone;
}
return (0);
}
/**
* initialize winsock
*/
void _os_socket_startup(void) {
WORD minver;
int err;
minver = MAKEWORD( 2, 2 );
err = WSAStartup( minver, &w32_wsadata );
if ( err != 0 ) {
DPRINTF(E_FATAL,L_MISC,"Could not initialize winsock\n");
}
}
/**
* deinitialize winsock
*/
void _os_socket_shutdown(void) {
WSACleanup();
}
/* COMPAT FUNCTIONS */
time_t timegm(struct tm *tm) {
time_t ret;
char *tz;
char buffer[255];
tz = getenv("TZ");
_putenv("TZ=UTC0");
_tzset();
ret = mktime(tm);
if(tz)
sprintf(buffer,"TZ=%s",tz);
else
strcpy(buffer,"TZ=");
_putenv(buffer);
_tzset();
return ret;
}
/* opendir/closedir/readdir emulation taken from emacs. Thanks. :) */
DIR *os_opendir(char *filename) {
DIR *dirp;
/* Opening is done by FindFirstFile. However, a read is inherent to
this operation, so we defer the open until read time. */
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
return NULL;
dirp->dir_find_handle = INVALID_HANDLE_VALUE;
dirp->dd_fd = 0;
dirp->dd_loc = 0;
dirp->dd_size = 0;
strncpy (dirp->dir_pathname, filename,_MAX_PATH);
dirp->dir_pathname[_MAX_PATH] = '\0';
return dirp;
}
void os_closedir(DIR *dirp) {
/* If we have a find-handle open, close it. */
if (dirp->dir_find_handle != INVALID_HANDLE_VALUE) {
FindClose(dirp->dir_find_handle);
}
free((char *) dirp);
}
int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
char filename[MAXNAMLEN + 3];
int ln;
strcpy (filename, dirp->dir_pathname);
ln = (int) strlen (filename) - 1;
if(filename[ln] != '\\')
strcat (filename, "\\");
strcat (filename, "*");
dirp->dir_find_handle = FindFirstFile (filename, &dirp->dir_find_data);
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
return 2;
}
} else {
if (!FindNextFile (dirp->dir_find_handle, &dirp->dir_find_data)) {
*result = NULL;
return 0;
}
}
/* Emacs never uses this value, so don't bother making it match
value returned by stat(). */
entry->d_ino = 1;
entry->d_namlen = (int) strlen (dirp->dir_find_data.cFileName);
entry->d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
entry->d_namlen - entry->d_namlen % 4;
strcpy (entry->d_name, dirp->dir_find_data.cFileName);
/*
if (dir_is_fat)
_strlwr (dir_static.d_name);
else if (!NILP (Vw32_downcase_file_names)) {
register char *p;
for (p = dir_static.d_name; *p; p++)
if (*p >= 'a' && *p <= 'z')
break;
if (!*p)
_strlwr (dir_static.d_name);
}
*/
*result = entry;
return 0;
}
/* can't be worse then strerror */
char *os_strerror (int error_no) {
static char buf[500];
if (error_no == 0)
error_no = GetLastError ();
buf[0] = '\0';
if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
error_no,
0, /* choose most suitable language */
buf, sizeof (buf), NULL))
sprintf (buf, "w32 error %u", error_no);
return buf;
}
/**
* get the default config path. there might be an argument to be made
* for using the install path as determined by registry, but might
* just be easiest to grab the directory the executable is running from
*
* @returns path to config file (from static buffer)
*/
char *os_configpath(void) {
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char working_dir[_MAX_PATH];
GetModuleFileName(NULL,os_config_file,MAX_PATH);
_splitpath(os_config_file,drive,dir,NULL,NULL);
_makepath(os_config_file,drive,dir,"mt-daapd","conf");
_makepath(working_dir,drive,dir,NULL,NULL);
if(_chdir(working_dir) == -1) {
DPRINTF(E_LOG,L_MISC,"Could not chdir to %s... using c:\\\n",working_dir);
if(_chdir("c:\\") == -1) {
DPRINTF(E_FATAL,L_MISC,"Could not chdir to c:\\... aborting\n");
}
}
DPRINTF(E_DBG,L_MISC,"Using config file %s\n",os_config_file);
return os_config_file;
}
/**
* Lock the mutex. This is used for initialization stuff, among
* other things (?)
*/
void _os_lock(void) {
int err;
if((err=pthread_mutex_lock(&os_mutex))) {
DPRINTF(E_FATAL,L_MISC,"Cannot lock mutex\n");
}
}
/**
* Unlock the os mutex
*/
void _os_unlock(void) {
int err;
if((err=pthread_mutex_unlock(&os_mutex))) {
DPRINTF(E_FATAL,L_MISC,"Cannot unlock mutex\n");
}
}

66
src/os-win32.h Normal file
View File

@ -0,0 +1,66 @@
/*
* $Id$
*
* os glue stuff, for functions that vary too greatly between
* win32 and unix
*/
#ifndef _OS_WIN32_H_
#define _OS_WIN32_H_
#include "stdlib.h"
#define MAXNAMLEN 255
#define DIRBLKSIZ 512
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
struct dirent { /* data from readdir() */
long d_ino; /* inode number of entry */
unsigned short d_reclen; /* length of this record */
unsigned short d_namlen; /* length of string in d_name */
char d_name[MAXNAMLEN+1]; /* name of file */
};
typedef struct {
int dd_fd; /* file descriptor */
int dd_loc; /* offset in block */
int dd_size; /* amount of valid data */
char dd_buf[DIRBLKSIZ]; /* directory block */
HANDLE dir_find_handle;
char dir_pathname[_MAX_PATH+1];
WIN32_FIND_DATA dir_find_data;
} DIR;
/* win32-specific functions -- set up service, etc */
extern int os_register(void);
extern int os_unregister(void);
extern char *os_configpath(void);
/* replacements for socket functions */
extern int os_opensocket(unsigned short port);
extern int os_acceptsocket(int fd, char *hostn, int hostnsize);
extern int os_shutdown(int fd, int how);
extern int os_waitfdtimed(int fd, struct timeval end);
extern int os_close(int fd);
extern int os_open(const char *filename, int oflag);
extern int os_read(int fd,void *buffer,unsigned int count);
extern int os_write(int fd, void *buffer, unsigned int count);
extern int os_getuid(void);
/* missing win32 functions */
extern char *os_strsep(char **stringp, const char *delim);
extern char *os_realpath(const char *pathname, char *resolved_path);
extern int os_gettimeofday (struct timeval *tv, struct timezone* tz);
extern int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
extern void os_closedir(DIR *dirp);
extern DIR *os_opendir(char *filename);
extern time_t timegm(struct tm *tm);
extern char *os_strerror (int error_no);
#endif /* _OS_WIN32_H_ */

41
src/os.h Normal file
View File

@ -0,0 +1,41 @@
/*
* $Id$
* Abstract os interface for non-unix platforms
*
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _OS_H_
#define _OS_H_
/* backgrounding, signal handling, etc */
extern int os_init(int foreground);
extern void os_deinit(void);
/* system native logging functions */
extern int os_opensyslog(void);
extern int os_closesyslog(void);
extern int os_syslog(int level, char *msg);
#ifdef WIN32
# include "os-win32.h"
#else
# include "os-unix.h"
#endif
#endif

View File

@ -17,66 +17,66 @@ static void query_free(query_node_t* query);
static int query_build_clause(query_node_t *query, char **current, int *size);
static const query_field_t *find_field(const char* name,
const query_field_t* fields);
const query_field_t* fields);
// static int arith_query(query_node_t* query, void* target);
// static int string_query(query_node_t* query, void* target);
static query_node_t *match_specifier(const char* query,
const char** cursor,
const query_field_t* fields);
const char** cursor,
const query_field_t* fields);
static query_node_t *group_match(const char* query,
const char** cursor,
const query_field_t* fields);
const char** cursor,
const query_field_t* fields);
static query_node_t *single_match(const char* query,
const char** cursor,
const query_field_t* fields);
const char** cursor,
const query_field_t* fields);
static int get_field_name(const char** pcursor,
const char* query,
char* name,
int len);
const char* query,
char* name,
int len);
static query_node_t *match_number(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query);
char not, char opcode,
const char** pcursor,
const char* query);
static query_node_t *match_string(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query);
char not, char opcode,
const char** pcursor,
const char* query);
char *query_unescape(const char* query);
static query_field_t song_fields[] = {
{ qft_string, "dmap.itemname", "title" },
{ qft_i32, "dmap.itemid", "id" },
{ qft_string, "daap.songalbum", "album" },
{ qft_string, "daap.songartist", "artist" },
{ qft_i32, "daap.songbitrate", "bitrate" },
{ qft_string, "daap.songcomment", "comment" },
{ qft_i32, "daap.songcompilation", "compilation" },
{ qft_string, "daap.songcomposer", "composer" },
{ qft_i32, "daap.songdatakind", "data_kind" },
{ qft_string, "daap.songdataurl", "url" },
{ qft_i32, "daap.songdateadded", "time_added" },
{ qft_i32, "daap.songdatemodified","time_modified" },
{ qft_string, "daap.songdescription", "description" },
{ qft_i32, "daap.songdisccount", "total_discs" },
{ qft_i32, "daap.songdiscnumber", "disc" },
{ qft_string, "daap.songformat", "type" },
{ qft_string, "daap.songgenre", "genre" },
{ qft_i32, "daap.songsamplerate", "samplerate" },
{ qft_i32, "daap.songsize", "file_size" },
// { qft_i32_const, "daap.songstarttime", 0 },
{ qft_i32, "daap.songstoptime", "song_length" },
{ qft_i32, "daap.songtime", "song_length" },
{ qft_i32, "daap.songtrackcount", "total_tracks" },
{ qft_i32, "daap.songtracknumber", "track" },
{ qft_i32, "daap.songyear", "year" },
static query_field_t song_fields[] = {
{ qft_string, "dmap.itemname", "title" },
{ qft_i32, "dmap.itemid", "id" },
{ qft_string, "daap.songalbum", "album" },
{ qft_string, "daap.songartist", "artist" },
{ qft_i32, "daap.songbitrate", "bitrate" },
{ qft_string, "daap.songcomment", "comment" },
{ qft_i32, "daap.songcompilation", "compilation" },
{ qft_string, "daap.songcomposer", "composer" },
{ qft_i32, "daap.songdatakind", "data_kind" },
{ qft_string, "daap.songdataurl", "url" },
{ qft_i32, "daap.songdateadded", "time_added" },
{ qft_i32, "daap.songdatemodified","time_modified" },
{ qft_string, "daap.songdescription", "description" },
{ qft_i32, "daap.songdisccount", "total_discs" },
{ qft_i32, "daap.songdiscnumber", "disc" },
{ qft_string, "daap.songformat", "type" },
{ qft_string, "daap.songgenre", "genre" },
{ qft_i32, "daap.songsamplerate", "samplerate" },
{ qft_i32, "daap.songsize", "file_size" },
// { qft_i32_const, "daap.songstarttime", 0 },
{ qft_i32, "daap.songstoptime", "song_length" },
{ qft_i32, "daap.songtime", "song_length" },
{ qft_i32, "daap.songtrackcount", "total_tracks" },
{ qft_i32, "daap.songtracknumber", "track" },
{ qft_i32, "daap.songyear", "year" },
{ 0, NULL, NULL }
};
@ -87,22 +87,22 @@ char *query_sql_escape(char *term) {
src=term;
while(*src) {
new_size++;
if(*src == '\'')
new_size++;
src++;
new_size++;
if(*src == '\'')
new_size++;
src++;
}
src=term;
pnew=(char*)malloc(new_size+1);
if(!pnew)
return pnew;
return pnew;
dst=pnew;
while(*src) {
if(*src == '\'')
*dst++='\'';
*dst++=*src++;
if(*src == '\'')
*dst++='\'';
*dst++=*src++;
}
*dst='\0';
@ -118,130 +118,130 @@ char *query_build_sql(char *query) {
DPRINTF(E_DBG,L_QRY,"Building query for %s\n",query);
pquery=query_build(query);
if(pquery) {
if(!query_build_clause(pquery,&sqlptr,&size)) {
query_free(pquery);
DPRINTF(E_DBG,L_QRY,"Built query: %s\n",sql);
return strdup(sql);
}
DPRINTF(E_DBG,L_QRY,"Error converting query to SQL\n");
query_free(pquery);
if(!query_build_clause(pquery,&sqlptr,&size)) {
query_free(pquery);
DPRINTF(E_DBG,L_QRY,"Built query: %s\n",sql);
return strdup(sql);
}
DPRINTF(E_DBG,L_QRY,"Error converting query to SQL\n");
query_free(pquery);
} else {
DPRINTF(E_DBG,L_QRY,"Error building query\n");
DPRINTF(E_DBG,L_QRY,"Error building query\n");
}
return NULL;
}
query_node_t* query_build(const char* query) {
query_node_t* left = 0;
char* raw = (char*)query; //query_unescape(query);
const char* cursor = raw;
query_node_t* right = 0;
query_type_t join;
query_node_t* left = 0;
char* raw = (char*)query; //query_unescape(query);
const char* cursor = raw;
query_node_t* right = 0;
query_type_t join;
if(0 == (left = match_specifier(query, &cursor, song_fields)))
goto error;
goto error;
while(*cursor)
{
query_node_t* con;
query_node_t* con;
switch(*cursor)
{
case '+':
case ' ': join = qot_and; break;
case ',': join = qot_or; break;
default:
DPRINTF(E_LOG,L_QRY, "Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - raw, raw);
goto error;
}
switch(*cursor)
{
case '+':
case ' ': join = qot_and; break;
case ',': join = qot_or; break;
default:
DPRINTF(E_LOG,L_QRY, "Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - raw, raw);
goto error;
}
cursor++;
cursor++;
if(0 == (right = match_specifier(raw, &cursor, song_fields)))
goto error;
if(0 == (right = match_specifier(raw, &cursor, song_fields)))
goto error;
con = (query_node_t*) calloc(1, sizeof(*con));
con->type = join;
con->left.node = left;
con->right.node = right;
con = (query_node_t*) calloc(1, sizeof(*con));
con->type = join;
con->left.node = left;
con->right.node = right;
left = con;
left = con;
}
if(query != raw)
free(raw);
free(raw);
return left;
error:
if(left != 0)
query_free(left);
query_free(left);
if(raw != query)
free(raw);
free(raw);
return NULL;
}
static query_node_t* match_specifier(const char* query,
const char** cursor,
const query_field_t* fields) {
static query_node_t* match_specifier(const char* query,
const char** cursor,
const query_field_t* fields) {
switch(**cursor) {
case '\'':
return single_match(query, cursor, fields);
case '(':
return group_match(query, cursor, fields);
case '\'':
return single_match(query, cursor, fields);
case '(':
return group_match(query, cursor, fields);
}
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
**cursor, **cursor, *cursor - query, query);
**cursor, **cursor, *cursor - query, query);
return NULL;
}
static query_node_t* group_match(const char* query,
const char** pcursor,
const query_field_t* fields)
static query_node_t* group_match(const char* query,
const char** pcursor,
const query_field_t* fields)
{
query_node_t* left = 0;
query_node_t* right = 0;
query_node_t* join = 0;
query_type_t opcode;
const char* cursor = *pcursor;
query_node_t* left = 0;
query_node_t* right = 0;
query_node_t* join = 0;
query_type_t opcode;
const char* cursor = *pcursor;
/* skip the opening ')' */
++cursor;
if(0 == (left = single_match(query, &cursor, fields)))
return NULL;
return NULL;
switch(*cursor)
{
case '+':
case ' ':
opcode = qot_and;
break;
opcode = qot_and;
break;
case ',':
opcode = qot_or;
break;
opcode = qot_or;
break;
default:
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
goto error;
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
goto error;
}
if(0 == (right = single_match(query, &cursor, fields)))
goto error;
goto error;
if(*cursor != ')')
{
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
goto error;
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
goto error;
}
*pcursor = cursor + 1;
join = (query_node_t*) calloc(1, sizeof(*join));
@ -253,100 +253,100 @@ static query_node_t* group_match(const char* query,
error:
if(0 != left)
query_free(left);
query_free(left);
if(0 != right)
query_free(right);
query_free(right);
return 0;
}
static query_node_t* single_match(const char* query,
const char** pcursor,
const query_field_t* fields)
static query_node_t* single_match(const char* query,
const char** pcursor,
const query_field_t* fields)
{
char fname[64];
const query_field_t* field;
char not = 0;
char op = 0;
query_node_t* node = 0;
char fname[64];
const query_field_t* field;
char not = 0;
char op = 0;
query_node_t* node = 0;
/* skip opening ' */
(*pcursor)++;
/* collect the field name */
if(!get_field_name(pcursor, query, fname, sizeof(fname)))
return NULL;
return NULL;
if(**pcursor == '!')
{
not = '!';
++(*pcursor);
not = '!';
++(*pcursor);
}
if(strchr(":+- ", **pcursor))
{
op = **pcursor;
++(*pcursor);
op = **pcursor;
++(*pcursor);
}
else
{
DPRINTF(E_LOG,L_QRY,"Illegal Operator: %c (0%o) at index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
return NULL;
DPRINTF(E_LOG,L_QRY,"Illegal Operator: %c (0%o) at index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
return NULL;
}
if(0 == (field = find_field(fname, fields)))
{
DPRINTF(E_LOG,L_QRY,"Unknown field: %s\n", fname);
return NULL;
DPRINTF(E_LOG,L_QRY,"Unknown field: %s\n", fname);
return NULL;
}
switch(field->type)
{
case qft_i32:
case qft_i64:
node = match_number(field, not, op, pcursor, query);
break;
node = match_number(field, not, op, pcursor, query);
break;
case qft_string:
node = match_string(field, not, op, pcursor, query);
break;
node = match_string(field, not, op, pcursor, query);
break;
default:
DPRINTF(E_LOG,L_QRY,"Invalid field type: %d\n", field->type);
break;
DPRINTF(E_LOG,L_QRY,"Invalid field type: %d\n", field->type);
break;
}
if(**pcursor != '\'')
{
DPRINTF(E_LOG,L_QRY,"Illegal Character: %c (0%o) index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
query_free(node);
node = 0;
DPRINTF(E_LOG,L_QRY,"Illegal Character: %c (0%o) index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
query_free(node);
node = 0;
}
else
++(*pcursor);
++(*pcursor);
return node;
}
static int get_field_name(const char** pcursor,
const char* query,
char* name,
int len) {
const char* cursor = *pcursor;
const char* query,
char* name,
int len) {
const char* cursor = *pcursor;
if(!isalpha(*cursor))
return 0;
return 0;
while(isalpha(*cursor) || *cursor == '.') {
if(--len <= 0) {
DPRINTF(E_LOG,L_QRY,"token length exceeded at offset %d: %s\n",
cursor - query, query);
return 0;
}
if(--len <= 0) {
DPRINTF(E_LOG,L_QRY,"token length exceeded at offset %d: %s\n",
cursor - query, query);
return 0;
}
*name++ = *cursor++;
*name++ = *cursor++;
}
*pcursor = cursor;
@ -356,25 +356,25 @@ static int get_field_name(const char** pcursor,
return 1;
}
static query_node_t* match_number(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query)
static query_node_t* match_number(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query)
{
query_node_t* node = (query_node_t*) calloc(1, sizeof(*node));
query_node_t* node = (query_node_t*) calloc(1, sizeof(*node));
switch(opcode)
{
case ':':
node->type = not ? qot_ne : qot_eq;
break;
node->type = not ? qot_ne : qot_eq;
break;
case '+':
case ' ':
node->type = not ? qot_le : qot_gt;
break;
node->type = not ? qot_le : qot_gt;
break;
case '-':
node->type = not ? qot_ge : qot_lt;
break;
node->type = not ? qot_ge : qot_lt;
break;
}
node->left.field = field;
@ -382,77 +382,77 @@ static query_node_t* match_number(const query_field_t* field,
switch(field->type)
{
case qft_i32:
node->right.i32 = strtol(*pcursor, (char**) pcursor, 10);
break;
node->right.i32 = strtol(*pcursor, (char**) pcursor, 10);
break;
case qft_i64:
node->right.i64 = strtoll(*pcursor, (char**) pcursor, 10);
break;
node->right.i64 = strtoll(*pcursor, (char**) pcursor, 10);
break;
default:
DPRINTF(E_LOG,L_QRY,"Bad field type -- invalid query\n");
break;
DPRINTF(E_LOG,L_QRY,"Bad field type -- invalid query\n");
break;
}
if(**pcursor != '\'')
{
DPRINTF(E_LOG,L_QRY,"Illegal char in number '%c' (0%o) at index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
free(node);
return 0;
DPRINTF(E_LOG,L_QRY,"Illegal char in number '%c' (0%o) at index %d: %s\n",
**pcursor, **pcursor, *pcursor - query, query);
free(node);
return 0;
}
return node;
}
static query_node_t* match_string(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query)
static query_node_t* match_string(const query_field_t* field,
char not, char opcode,
const char** pcursor,
const char* query)
{
char match[256];
char* dst = match;
int left = sizeof(match);
const char* cursor = *pcursor;
query_type_t op = qot_is;
query_node_t* node;
char match[256];
char* dst = match;
int left = sizeof(match);
const char* cursor = *pcursor;
query_type_t op = qot_is;
query_node_t* node;
if(opcode != ':') {
DPRINTF(E_LOG,L_QRY,"Illegal operation on string: %c at index %d: %s\n",
opcode, cursor - query - 1);
return NULL;
DPRINTF(E_LOG,L_QRY,"Illegal operation on string: %c at index %d: %s\n",
opcode, cursor - query - 1);
return NULL;
}
if(*cursor == '*') {
op = qot_ends;
cursor++;
op = qot_ends;
cursor++;
}
while(*cursor && *cursor != '\'') {
if(--left == 0) {
DPRINTF(E_LOG,L_QRY,"string too long at index %d: %s\n",
cursor - query, query);
return NULL;
}
if(--left == 0) {
DPRINTF(E_LOG,L_QRY,"string too long at index %d: %s\n",
cursor - query, query);
return NULL;
}
if(*cursor == '\\') {
switch(*++cursor) {
case '*':
case '\'':
case '\\':
*dst++ = *cursor++;
break;
default:
DPRINTF(E_LOG,L_QRY,"Illegal escape: %c (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
return NULL;
}
} else {
*dst++ = *cursor++;
}
if(*cursor == '\\') {
switch(*++cursor) {
case '*':
case '\'':
case '\\':
*dst++ = *cursor++;
break;
default:
DPRINTF(E_LOG,L_QRY,"Illegal escape: %c (0%o) at index %d: %s\n",
*cursor, *cursor, cursor - query, query);
return NULL;
}
} else {
*dst++ = *cursor++;
}
}
if(dst[-1] == '*') {
op = (op == qot_is) ? qot_begins : qot_contains;
dst--;
op = (op == qot_is) ? qot_begins : qot_contains;
dst--;
}
*dst = 0;
@ -471,57 +471,57 @@ static query_node_t* match_string(const query_field_t* field,
void query_free(query_node_t* query) {
if(0 != query)
{
switch(query->type)
{
// conjunction
case qot_and:
case qot_or:
query_free(query->left.node);
query_free(query->right.node);
break;
switch(query->type)
{
// conjunction
case qot_and:
case qot_or:
query_free(query->left.node);
query_free(query->right.node);
break;
// negation
case qot_not:
query_free(query->left.node);
break;
// negation
case qot_not:
query_free(query->left.node);
break;
// arithmetic
case qot_eq:
case qot_ne:
case qot_le:
case qot_lt:
case qot_ge:
case qot_gt:
break;
// arithmetic
case qot_eq:
case qot_ne:
case qot_le:
case qot_lt:
case qot_ge:
case qot_gt:
break;
// string
case qot_is:
case qot_begins:
case qot_ends:
case qot_contains:
free(query->right.str);
break;
// string
case qot_is:
case qot_begins:
case qot_ends:
case qot_contains:
free(query->right.str);
break;
// constants
case qot_const:
break;
default:
DPRINTF(E_LOG,L_QRY,"Illegal query type: %d\n", query->type);
break;
}
// constants
case qot_const:
break;
default:
DPRINTF(E_LOG,L_QRY,"Illegal query type: %d\n", query->type);
break;
}
free(query);
free(query);
}
}
static const query_field_t* find_field(const char* name, const query_field_t* fields) {
while(fields->name && strcasecmp(fields->name, name))
fields++;
fields++;
if(fields->name == 0) {
DPRINTF(E_LOG,L_QRY,"Illegal query field: %s\n", name);
return NULL;
DPRINTF(E_LOG,L_QRY,"Illegal query field: %s\n", name);
return NULL;
}
return fields;
@ -536,8 +536,8 @@ int query_add_string(char **current, int *size, char *fmt, ...) {
va_end(ap);
if(write_size > *size) {
*size=0;
return 0;
*size=0;
return 0;
}
*size = *size - write_size;
@ -546,72 +546,72 @@ int query_add_string(char **current, int *size, char *fmt, ...) {
int query_build_clause(query_node_t *query, char **current, int *size) {
char* labels[] = {
"NOP",
"AND",
"OR",
"NOT",
"=",
"<>",
"<=",
"<",
">=",
">",
"=",
" (%s LIKE '%s%%') ",
" (%s LIKE '%%%s') ",
" (%s LIKE '%%%s%%') ",
"constant"
"NOP",
"AND",
"OR",
"NOT",
"=",
"<>",
"<=",
"<",
">=",
">",
"=",
" (%s LIKE '%s%%') ",
" (%s LIKE '%%%s') ",
" (%s LIKE '%%%s%%') ",
"constant"
};
switch(query->type) {
case qot_and:
case qot_or:
if(*size) (*current) += query_add_string(current,size," (");
if(query_build_clause(query->left.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size," %s ", labels[query->type]);
if(query_build_clause(query->right.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size,") ");
break;
if(*size) (*current) += query_add_string(current,size," (");
if(query_build_clause(query->left.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size," %s ", labels[query->type]);
if(query_build_clause(query->right.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size,") ");
break;
case qot_not:
if(*size) (*current) += query_add_string(current,size," (NOT ");
if(query_build_clause(query->left.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size,") ");
break;
if(*size) (*current) += query_add_string(current,size," (NOT ");
if(query_build_clause(query->left.node,current,size)) return 1;
if(*size) (*current) += query_add_string(current,size,") ");
break;
case qot_eq:
case qot_ne:
case qot_le:
case qot_lt:
case qot_ge:
case qot_gt:
if(*size) (*current) += query_add_string(current,size," (%s %s ",
query->left.field->fieldname,
labels[query->type]);
if(query->left.field->type == qft_i32) {
if(*size) (*current) += query_add_string(current,size," %d) ",query->right.i32);
} else {
if(*size) (*current) += query_add_string(current,size," %ll) ",query->right.i64);
}
break;
if(*size) (*current) += query_add_string(current,size," (%s %s ",
query->left.field->fieldname,
labels[query->type]);
if(query->left.field->type == qft_i32) {
if(*size) (*current) += query_add_string(current,size," %d) ",query->right.i32);
} else {
if(*size) (*current) += query_add_string(current,size," %ll) ",query->right.i64);
}
break;
case qot_is:
if(*size)(*current) += query_add_string(current,size," (%s='%s') ",
query->left.field->fieldname,
query->right.str);
break;
if(*size)(*current) += query_add_string(current,size," (%s='%s') ",
query->left.field->fieldname,
query->right.str);
break;
case qot_begins:
case qot_ends:
case qot_contains:
if(*size)(*current) += query_add_string(current,size,labels[query->type],
query->left.field->fieldname,
query->right.str);
break;
if(*size)(*current) += query_add_string(current,size,labels[query->type],
query->left.field->fieldname,
query->right.str);
break;
case qot_const: /* Not sure what this would be for */
break;
break;
default:
break;
break;
}
return 0;
@ -619,36 +619,36 @@ int query_build_clause(query_node_t *query, char **current, int *size) {
char* query_unescape(const char* src) {
char* copy = malloc(strlen(src) + 1);
char* dst = copy;
char* copy = malloc(strlen(src) + 1);
char* dst = copy;
while(*src)
{
if(*src == '%')
{
int val = 0;
if(*src == '%')
{
int val = 0;
if(*++src)
{
if(isdigit(*src))
val = val * 16 + *src - '0';
else
val = val * 16 + tolower(*src) - 'a' + 10;
}
if(*++src)
{
if(isdigit(*src))
val = val * 16 + *src - '0';
else
val = val * 16 + tolower(*src) - 'a' + 10;
}
if(*++src)
{
if(isdigit(*src))
val = val * 16 + *src - '0';
else
val = val * 16 + tolower(*src) - 'a' + 10;
}
if(*++src)
{
if(isdigit(*src))
val = val * 16 + *src - '0';
else
val = val * 16 + tolower(*src) - 'a' + 10;
}
src++;
*dst++ = val;
}
else
*dst++ = *src++;
src++;
*dst++ = val;
}
else
*dst++ = *src++;
}
*dst++ = 0;

View File

@ -41,25 +41,25 @@ typedef struct query_field_ query_field_t;
struct query_field_
{
query_type_t type;
const char* name;
const char* name;
const char* fieldname;
};
typedef struct query_node_ query_node_t;
struct query_node_
{
query_type_t type;
query_type_t type;
union {
query_node_t* node;
const query_field_t* field;
int constant;
} left;
query_node_t* node;
const query_field_t* field;
int constant;
} left;
union {
query_node_t* node;
int i32;
long long i64;
char* str;
} right;
query_node_t* node;
int i32;
long long i64;
char* str;
} right;
};
extern char *query_build_sql(char *query);

File diff suppressed because it is too large Load Diff

View File

@ -39,10 +39,10 @@
* compiled in, RB_CMP only needs to take two arguments. If your
* content type is not a pointer, define INLINE to get direct access.
*/
#define rbdata_t void
#define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
#define rbdata_t void
#define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
#undef RB_INLINE
#define RB_ENTRY(name) rb##name
#define RB_ENTRY(name) rb##name
#endif /* RB_CUSTOMIZE */
#ifndef RB_STATIC
@ -50,16 +50,16 @@
#endif
/* Modes for rblookup */
#define RB_NONE -1 /* None of those below */
#define RB_LUEQUAL 0 /* Only exact match */
#define RB_LUGTEQ 1 /* Exact match or greater */
#define RB_LULTEQ 2 /* Exact match or less */
#define RB_LULESS 3 /* Less than key (not equal to) */
#define RB_LUGREAT 4 /* Greater than key (not equal to) */
#define RB_LUNEXT 5 /* Next key after current */
#define RB_LUPREV 6 /* Prev key before current */
#define RB_LUFIRST 7 /* First key in index */
#define RB_LULAST 8 /* Last key in index */
#define RB_NONE -1 /* None of those below */
#define RB_LUEQUAL 0 /* Only exact match */
#define RB_LUGTEQ 1 /* Exact match or greater */
#define RB_LULTEQ 2 /* Exact match or less */
#define RB_LULESS 3 /* Less than key (not equal to) */
#define RB_LUGREAT 4 /* Greater than key (not equal to) */
#define RB_LUNEXT 5 /* Next key after current */
#define RB_LUPREV 6 /* Prev key before current */
#define RB_LUFIRST 7 /* First key in index */
#define RB_LULAST 8 /* Last key in index */
/* For rbwalk - pinched from search.h */
typedef enum
@ -80,18 +80,18 @@ const struct RB_ENTRY(node) *nextp;
struct RB_ENTRY(tree) {
#ifndef RB_CUSTOMIZE
/* comparison routine */
/* comparison routine */
int (*rb_cmp)(const void *, const void *, const void *);
/* config data to be passed to rb_cmp */
/* config data to be passed to rb_cmp */
const void *rb_config;
/* root of tree */
/* root of tree */
#endif /* RB_CUSTOMIZE */
struct RB_ENTRY(node) *rb_root;
};
#ifndef RB_CUSTOMIZE
RB_STATIC struct RB_ENTRY(tree) *rbinit(int (*)(const void *, const void *, const void *),
const void *);
const void *);
#else
RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void);
#endif /* RB_CUSTOMIZE */
@ -118,8 +118,8 @@ RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *);
#ifndef no_walk
RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *,
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
void *);
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
void *);
#endif
#ifndef no_readlist
@ -138,6 +138,12 @@ RB_STATIC void RB_ENTRY(closelist)(RBLIST *);
/*
*
* $Log$
* Revision 1.4 2006/02/26 08:46:24 rpedde
* Merged win32-branch
*
* Revision 1.3.2.1 2006/02/26 08:28:35 rpedde
* unix fixes from win32 port
*
* Revision 1.3 2005/05/21 05:56:09 rpedde
* for quick translation from itunes song id to mt-daapd song id
*

View File

@ -33,6 +33,7 @@
#include <pthread.h>
#include "err.h"
#include "os-unix.h"
#include "rend-unix.h"
pthread_t rend_tid;
@ -48,14 +49,14 @@ void rend_callback(void);
* Callback function for mDNS stuff
*/
static sw_result rend_howl_reply(sw_discovery discovery,
sw_discovery_publish_status status,
sw_discovery_oid oid,
sw_opaque extra) {
sw_discovery_publish_status status,
sw_discovery_oid oid,
sw_opaque extra) {
static sw_string status_text[] = {
"started",
"stopped",
"name collision",
"invalid"
"started",
"stopped",
"name collision",
"invalid"
};
DPRINTF(E_DBG,L_REND,"Publish reply: %s\n",status_text[status]);
@ -75,20 +76,20 @@ int rend_private_init(char *user) {
signal(SIGHUP, SIG_IGN); // SIGHUP might happen from a request to reload the daap server
if(sw_discovery_init(&rend_handle) != SW_OKAY) {
DPRINTF(E_WARN,L_REND,"Error initializing howl\n");
errno=EINVAL;
return -1;
DPRINTF(E_WARN,L_REND,"Error initializing howl\n");
errno=EINVAL;
return -1;
}
if(drop_privs(user))
return -1;
if(os_drop_privs(user))
return -1;
DPRINTF(E_DBG,L_REND,"Starting polling thread\n");
if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
/* should kill parent, too */
exit(EXIT_FAILURE);
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
/* should kill parent, too */
exit(EXIT_FAILURE);
}
DPRINTF(E_DBG,L_REND,"Entering runloop\n");
@ -109,21 +110,21 @@ void *rend_pipe_monitor(void* arg) {
int result;
while(1) {
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
FD_ZERO(&rset);
FD_SET(rend_pipe_to[RD_SIDE],&rset);
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
FD_ZERO(&rset);
FD_SET(rend_pipe_to[RD_SIDE],&rset);
/* sit in a select spin until there is data on the to fd */
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
errno != EINTR) {
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
rend_callback();
}
}
/* sit in a select spin until there is data on the to fd */
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
errno != EINTR) {
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
rend_callback();
}
}
DPRINTF(E_DBG,L_REND,"Select error!\n");
/* should really bail here */
DPRINTF(E_DBG,L_REND,"Select error!\n");
/* should really bail here */
}
}
@ -142,46 +143,46 @@ void rend_callback(void) {
/* here, we've seen the message, now we have to process it */
if(rend_read_message(&msg) != sizeof(msg)) {
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
exit(EXIT_FAILURE);
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
exit(EXIT_FAILURE);
}
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
if((result=sw_discovery_publish(rend_handle,
0, /* interface handle */
msg.name,
msg.type,
NULL, /* domain */
NULL, /* host */
msg.port,
"\011txtvers=1\034Database ID=beddab1edeadbea7", /* text record */
39, /* text record length */
rend_howl_reply,
NULL,
&rend_oid)) != SW_OKAY) {
DPRINTF(E_WARN,L_REND,"Error registering name\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
if((result=sw_discovery_publish(rend_handle,
0, /* interface handle */
msg.name,
msg.type,
NULL, /* domain */
NULL, /* host */
msg.port,
"\011txtvers=1\034Database ID=beddab1edeadbea7", /* text record */
39, /* text record length */
rend_howl_reply,
NULL,
&rend_oid)) != SW_OKAY) {
DPRINTF(E_WARN,L_REND,"Error registering name\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
case REND_MSG_TYPE_UNREGISTER:
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
rend_send_response(0);
//sw_rendezvous_stop_publish(rend_handle);
sw_discovery_fina(rend_handle);
break;
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
rend_send_response(0);
//sw_rendezvous_stop_publish(rend_handle);
sw_discovery_fina(rend_handle);
break;
case REND_MSG_TYPE_STATUS:
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
default:
break;
break;
}
}

View File

@ -35,6 +35,7 @@
#include "daapd.h"
#include "err.h"
#include "os-unix.h"
#include "rend-unix.h"
CFRunLoopRef rend_runloop;
@ -75,19 +76,19 @@ static int rend_addtorunloop(dns_service_discovery_ref client) {
mach_port_t port=DNSServiceDiscoveryMachPort(client);
if(!port)
return -1;
return -1;
else {
CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
Boolean shouldFreeInfo;
CFMachPortRef cfMachPort=CFMachPortCreateWithPort(kCFAllocatorDefault,
port, rend_handler,
&context, &shouldFreeInfo);
CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
Boolean shouldFreeInfo;
CFMachPortRef cfMachPort=CFMachPortCreateWithPort(kCFAllocatorDefault,
port, rend_handler,
&context, &shouldFreeInfo);
CFRunLoopSourceRef rls=CFMachPortCreateRunLoopSource(NULL,cfMachPort,0);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
rls,kCFRunLoopDefaultMode);
CFRelease(rls);
return 0;
CFRunLoopSourceRef rls=CFMachPortCreateRunLoopSource(NULL,cfMachPort,0);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
rls,kCFRunLoopDefaultMode);
CFRelease(rls);
return 0;
}
}
@ -97,14 +98,14 @@ static int rend_addtorunloop(dns_service_discovery_ref client) {
static void rend_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) {
switch(errorCode) {
case kDNSServiceDiscoveryNoError:
DPRINTF(E_DBG,L_REND,"Registered successfully\n");
break;
DPRINTF(E_DBG,L_REND,"Registered successfully\n");
break;
case kDNSServiceDiscoveryNameConflict:
DPRINTF(E_WARN,L_REND,"Error - name in use\n");
break;
DPRINTF(E_WARN,L_REND,"Error - name in use\n");
break;
default:
DPRINTF(E_WARN,L_REND,"Error %d\n",errorCode);
break;
DPRINTF(E_WARN,L_REND,"Error %d\n",errorCode);
break;
}
}
@ -117,23 +118,23 @@ void *rend_pipe_monitor(void* arg) {
while(1) {
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
FD_ZERO(&rset);
FD_SET(rend_pipe_to[RD_SIDE],&rset);
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
FD_ZERO(&rset);
FD_SET(rend_pipe_to[RD_SIDE],&rset);
/* sit in a select spin until there is data on the to fd */
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
errno != EINTR) {
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
CFRunLoopSourceSignal(rend_rls);
CFRunLoopWakeUp(rend_runloop);
sleep(1); /* force a reschedule, hopefully */
}
}
/* sit in a select spin until there is data on the to fd */
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
errno != EINTR) {
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
CFRunLoopSourceSignal(rend_rls);
CFRunLoopWakeUp(rend_runloop);
sleep(1); /* force a reschedule, hopefully */
}
}
DPRINTF(E_DBG,L_REND,"Select error!\n");
/* should really bail here */
DPRINTF(E_DBG,L_REND,"Select error!\n");
/* should really bail here */
}
}
@ -163,38 +164,38 @@ void rend_callback(void *info) {
/* here, we've seen the message, now we have to process it */
if(rend_read_message(&msg) != sizeof(msg)) {
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
exit(EXIT_FAILURE);
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
exit(EXIT_FAILURE);
}
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
usPort=msg.port;
dns_ref=DNSServiceRegistrationCreate(msg.name,msg.type,"",usPort,
"txtvers=1\001Database ID=bedabb1edeadbea7",rend_reply,nil);
if(rend_addtorunloop(dns_ref)) {
DPRINTF(E_WARN,L_REND,"Add to runloop failed\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
usPort=msg.port;
dns_ref=DNSServiceRegistrationCreate(msg.name,msg.type,"",usPort,
"txtvers=1\001Database ID=bedabb1edeadbea7",rend_reply,nil);
if(rend_addtorunloop(dns_ref)) {
DPRINTF(E_WARN,L_REND,"Add to runloop failed\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
case REND_MSG_TYPE_UNREGISTER:
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
rend_send_response(0);
rend_stoprunloop();
break;
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
rend_send_response(0);
rend_stoprunloop();
break;
case REND_MSG_TYPE_STATUS:
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
default:
break;
break;
}
}
@ -206,8 +207,8 @@ void rend_callback(void *info) {
int rend_private_init(char *user) {
CFRunLoopSourceContext context;
if(drop_privs(user)) /* shouldn't be running as root anyway */
return -1;
if(os_drop_privs(user)) /* shouldn't be running as root anyway */
return -1;
/* need a sigint handler */
DPRINTF(E_DBG,L_REND,"Starting rendezvous services\n");
@ -222,9 +223,9 @@ int rend_private_init(char *user) {
DPRINTF(E_DBG,L_REND,"Starting polling thread\n");
if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
/* should kill parent, too */
exit(EXIT_FAILURE);
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
/* should kill parent, too */
exit(EXIT_FAILURE);
}
DPRINTF(E_DBG,L_REND,"Starting runloop\n");

View File

@ -89,6 +89,15 @@
Change History (most recent first):
$Log$
Revision 1.28 2006/02/26 08:46:24 rpedde
Merged win32-branch
Revision 1.27.2.2 2006/02/26 08:28:35 rpedde
unix fixes from win32 port
Revision 1.27.2.1 2006/02/23 03:19:40 rpedde
First pass at win32 port.
Revision 1.27 2006/02/20 03:36:57 rpedde
Annoying fprintf
@ -188,11 +197,11 @@
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include <assert.h>
#include <stdio.h> // For printf()
#include <stdlib.h> // For exit() etc.
#include <string.h> // For strlen() etc.
#include <unistd.h> // For select()
#include <errno.h> // For errno, EINTR
#include <stdio.h> // For printf()
#include <stdlib.h> // For exit() etc.
#include <string.h> // For strlen() etc.
#include <unistd.h> // For select()
#include <errno.h> // For errno, EINTR
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
@ -201,6 +210,7 @@
#define __IN_ERR__
#include "daapd.h"
#include "err.h"
#include "os-unix.h"
#include "rend.h"
#include "rend-unix.h"
@ -211,12 +221,12 @@
typedef struct PosixNetworkInterface PosixNetworkInterface;
struct PosixNetworkInterface {
NetworkInterfaceInfo coreIntf;
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
int multicastSocket;
int multicastSocketv6;
NetworkInterfaceInfo coreIntf;
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
int multicastSocket;
int multicastSocketv6;
};
@ -291,52 +301,52 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
switch (status) {
case mStatus_NoError:
DPRINTF(E_DBG,L_REND,"Callback: Name Registered\n");
// Do nothing; our name was successfully registered. We may
// get more call backs in the future.
break;
DPRINTF(E_DBG,L_REND,"Callback: Name Registered\n");
// Do nothing; our name was successfully registered. We may
// get more call backs in the future.
break;
case mStatus_NameConflict:
DPRINTF(E_WARN,L_REND,"Callback: Name Conflict\n");
DPRINTF(E_WARN,L_REND,"Callback: Name Conflict\n");
// In the event of a conflict, this sample RegistrationCallback
// just calls mDNS_RenameAndReregisterService to automatically
// pick a new unique name for the service. For a device such as a
// printer, this may be appropriate. For a device with a user
// interface, and a screen, and a keyboard, the appropriate response
// may be to prompt the user and ask them to choose a new name for
// the service.
//
// Also, what do we do if mDNS_RenameAndReregisterService returns an
// error. Right now I have no place to send that error to.
// In the event of a conflict, this sample RegistrationCallback
// just calls mDNS_RenameAndReregisterService to automatically
// pick a new unique name for the service. For a device such as a
// printer, this may be appropriate. For a device with a user
// interface, and a screen, and a keyboard, the appropriate response
// may be to prompt the user and ask them to choose a new name for
// the service.
//
// Also, what do we do if mDNS_RenameAndReregisterService returns an
// error. Right now I have no place to send that error to.
status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
assert(status == mStatus_NoError);
break;
status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
assert(status == mStatus_NoError);
break;
case mStatus_MemFree:
DPRINTF(E_WARN,L_REND,"Callback: Memory Free\n");
DPRINTF(E_WARN,L_REND,"Callback: Memory Free\n");
// When debugging is enabled, make sure that thisRegistration
// is not on our gServiceList.
// When debugging is enabled, make sure that thisRegistration
// is not on our gServiceList.
#if defined(DEBUG)
{
PosixService *cursor;
{
PosixService *cursor;
cursor = gServiceList;
while (cursor != NULL) {
assert(&cursor->coreServ != thisRegistration);
cursor = cursor->next;
}
}
cursor = gServiceList;
while (cursor != NULL) {
assert(&cursor->coreServ != thisRegistration);
cursor = cursor->next;
}
}
#endif
free(thisRegistration);
break;
free(thisRegistration);
break;
default:
DPRINTF(E_WARN,L_REND,"Callback: Unknown Status %d\n",status);
break;
DPRINTF(E_WARN,L_REND,"Callback: Unknown Status %d\n",status);
break;
}
}
@ -344,11 +354,11 @@ static int gServiceID = 0;
static mStatus RegisterOneService(const char * richTextHostName,
const char * serviceType,
const char * serviceDomain,
const char * serviceDomain,
const mDNSu8 text[],
mDNSu16 textLen,
long portNumber,
mDNSInterfaceID id)
mDNSInterfaceID id)
{
mStatus status;
PosixService * thisServ;
@ -370,13 +380,13 @@ static mStatus RegisterOneService(const char * richTextHostName,
port.b[0] = (portNumber >> 8) & 0x0FF;
port.b[1] = (portNumber >> 0) & 0x0FF;;
status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
&name, &type, &domain,
NULL,
port,
text, textLen,
NULL, 0,
id,
RegistrationCallback, thisServ);
&name, &type, &domain,
NULL,
port,
text, textLen,
NULL, 0,
id,
RegistrationCallback, thisServ);
}
if (status == mStatus_NoError) {
thisServ->serviceID = gServiceID;
@ -385,13 +395,13 @@ static mStatus RegisterOneService(const char * richTextHostName,
thisServ->next = gServiceList;
gServiceList = thisServ;
DPRINTF(E_DBG,L_REND,
"Registered service %d, name '%s', type '%s', domain '%s', port %ld\n",
thisServ->serviceID,
richTextHostName,
serviceType,
serviceDomain,
portNumber);
DPRINTF(E_DBG,L_REND,
"Registered service %d, name '%s', type '%s', domain '%s', port %ld\n",
thisServ->serviceID,
richTextHostName,
serviceType,
serviceDomain,
portNumber);
} else {
if (thisServ != NULL) {
free(thisServ);
@ -413,8 +423,8 @@ static void DeregisterOurServices(void)
mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
DPRINTF(E_DBG,L_REND,"Deregistered service %d\n",
thisServ->serviceID);
DPRINTF(E_DBG,L_REND,"Deregistered service %d\n",
thisServ->serviceID);
}
}
@ -422,22 +432,22 @@ mDNSInterfaceID rend_get_interface_id(char *iface) {
PosixNetworkInterface *pni;
if(!iface)
return mDNSInterface_Any;
return mDNSInterface_Any;
if(!strlen(iface))
return mDNSInterface_Any;
return mDNSInterface_Any;
DPRINTF(E_LOG,L_REND,"Searching for interface %s\n",iface);
pni=(PosixNetworkInterface*)mDNSStorage.HostInterfaces;
while(pni) {
DPRINTF(E_INF,L_REND,"Found interface %s, index %d\n",pni->intfName,
pni->index);
if(strcasecmp(pni->intfName,iface) == 0) {
DPRINTF(E_INF,L_REND,"Found interface id: %d\n",pni->coreIntf.InterfaceID);
return pni->coreIntf.InterfaceID;
}
pni=(PosixNetworkInterface*)(pni->coreIntf.next);
DPRINTF(E_INF,L_REND,"Found interface %s, index %d\n",pni->intfName,
pni->index);
if(strcasecmp(pni->intfName,iface) == 0) {
DPRINTF(E_INF,L_REND,"Found interface id: %d\n",pni->coreIntf.InterfaceID);
return pni->coreIntf.InterfaceID;
}
pni=(PosixNetworkInterface*)(pni->coreIntf.next);
}
DPRINTF(E_INF,L_REND,"Could not find interface.\n");
@ -460,33 +470,33 @@ void rend_callback(void) {
/* here, we've seen the message, now we have to process it */
if((result=rend_read_message(&msg)) != sizeof(msg)) {
err=errno;
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
gStopNow=mDNStrue;
return;
err=errno;
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
gStopNow=mDNStrue;
return;
}
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
id=rend_get_interface_id(msg.interface);
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.name,msg.type,msg.port);
RegisterOneService(msg.name,msg.type,"local.","\011txtvers=1\034Database ID=beddab1edeadbea7",39,
msg.port,id);
rend_send_response(0); /* success */
break;
id=rend_get_interface_id(msg.iface);
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.name,msg.type,msg.port);
RegisterOneService(msg.name,msg.type,"local.","\011txtvers=1\034Database ID=beddab1edeadbea7",39,
msg.port,id);
rend_send_response(0); /* success */
break;
case REND_MSG_TYPE_UNREGISTER:
rend_send_response(1); /* error */
break;
rend_send_response(1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(E_INF,L_REND,"Stopping mDNS\n");
gStopNow = mDNStrue;
rend_send_response(0);
break;
DPRINTF(E_INF,L_REND,"Stopping mDNS\n");
gStopNow = mDNStrue;
rend_send_response(0);
break;
case REND_MSG_TYPE_STATUS:
rend_send_response(1);
break;
rend_send_response(1);
break;
default:
break;
break;
}
}
@ -497,63 +507,63 @@ int rend_private_init(char *user) {
mDNSBool result;
status = mDNS_Init(&mDNSStorage, &PlatformStorage,
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_AdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_AdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
if (status != mStatus_NoError) {
DPRINTF(E_FATAL,L_REND,"mDNS Error %d\n",status);
return(-1);
DPRINTF(E_FATAL,L_REND,"mDNS Error %d\n",status);
return(-1);
}
if(drop_privs(user))
return -1;
if(os_drop_privs(user))
return -1;
signal(SIGINT, HandleSigInt); // SIGINT is what you get for a Ctrl-C
signal(SIGQUIT, HandleSigQuit); // SIGQUIT is what you get for a Ctrl-\ (indeed)
signal(SIGHUP, SIG_IGN); // SIGHUP might happen from a request to reload the daap server
while (!gStopNow) {
int nfds = 1;
fd_set readfds;
struct timeval timeout;
int result;
// 1. Set up the fd_set as usual here.
// This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds);
FD_SET(rend_pipe_to[RD_SIDE],&readfds);
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
// so we set an effectively infinite timeout
timeout.tv_sec = 0x3FFFFFFF;
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
// 4. Call select as normal
DPRINTF(E_DBG,L_REND,"select(%d, %d.%06d)\n", nfds,
timeout.tv_sec, timeout.tv_usec);
result = select(nfds, &readfds, NULL, NULL, &timeout);
if (result < 0) {
if (errno != EINTR) gStopNow = mDNStrue;
DPRINTF(E_WARN,L_REND,"select() returned %d errno %d\n", result, errno);
} else {
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
// 6. This example client has no other work it needs to be doing,
// but a real client would do its work here
// ... (do work) ...
if(FD_ISSET(rend_pipe_to[RD_SIDE],&readfds)) {
rend_callback();
}
}
int nfds = 1;
fd_set readfds;
struct timeval timeout;
int result;
// 1. Set up the fd_set as usual here.
// This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds);
FD_SET(rend_pipe_to[RD_SIDE],&readfds);
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
// so we set an effectively infinite timeout
timeout.tv_sec = 0x3FFFFFFF;
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
// 4. Call select as normal
DPRINTF(E_DBG,L_REND,"select(%d, %d.%06d)\n", nfds,
timeout.tv_sec, timeout.tv_usec);
result = select(nfds, &readfds, NULL, NULL, &timeout);
if (result < 0) {
if (errno != EINTR) gStopNow = mDNStrue;
DPRINTF(E_WARN,L_REND,"select() returned %d errno %d\n", result, errno);
} else {
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
// 6. This example client has no other work it needs to be doing,
// but a real client would do its work here
// ... (do work) ...
if(FD_ISSET(rend_pipe_to[RD_SIDE],&readfds)) {
rend_callback();
}
}
}
DPRINTF(E_DBG,L_REND,"Exiting\n");
@ -567,7 +577,7 @@ int rend_private_init(char *user) {
result = 2;
}
DPRINTF(E_DBG,L_REND, "Finished with status %ld, result %d\n",
status, result);
status, result);
exit(result);
}

View File

@ -54,31 +54,31 @@ int rend_init(char *user) {
int fd;
if(pipe((int*)&rend_pipe_to) == -1)
return -1;
return -1;
if(pipe((int*)&rend_pipe_from) == -1) {
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
errno=err;
return -1;
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
errno=err;
return -1;
}
rend_pid=fork();
if(rend_pid==-1) {
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
close(rend_pipe_from[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
errno=err;
return -1;
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
close(rend_pipe_from[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
errno=err;
return -1;
}
if(rend_pid) { /* parent */
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
return 0;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
return 0;
}
/* child */
@ -100,17 +100,17 @@ int rend_init(char *user) {
#ifdef TIOCNOTTY
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(fd, TIOCNOTTY, (char *) NULL);
close(fd);
ioctl(fd, TIOCNOTTY, (char *) NULL);
close(fd);
}
#endif
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
// dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
// dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
errno = 0;
@ -159,20 +159,20 @@ int rend_stop(void) {
*
* register a rendezvous name
*/
int rend_register(char *name, char *type, int port, char *interface) {
int rend_register(char *name, char *type, int port, char *iface) {
REND_MESSAGE msg;
if((strlen(name)+1 > MAX_NAME_LEN) || (strlen(type)+1 > MAX_NAME_LEN)) {
DPRINTF(E_FATAL,L_REND,"Registration failed: name or type too long\n");
return -1;
DPRINTF(E_FATAL,L_REND,"Registration failed: name or type too long\n");
return -1;
}
memset((void*)&msg,0x00,sizeof(msg)); /* shut valgrind up */
msg.cmd=REND_MSG_TYPE_REGISTER;
strncpy(msg.name,name,MAX_NAME_LEN-1);
strncpy(msg.type,type,MAX_NAME_LEN-1);
if(interface)
strncpy(msg.interface,interface,MAX_IFACE_NAME_LEN-1);
if(iface)
strncpy(msg.iface,iface,MAX_IFACE_NAME_LEN-1);
msg.port=port;
@ -197,10 +197,10 @@ int rend_send_message(REND_MESSAGE *pmsg) {
int retval;
if(r_write(rend_pipe_to[WR_SIDE],pmsg,sizeof(REND_MESSAGE)) == -1)
return -1;
return -1;
if((retval=r_read(rend_pipe_from[RD_SIDE],&retval,sizeof(int)) == -1))
return -1;
return -1;
return retval;
}

View File

@ -32,7 +32,7 @@ typedef struct tag_rend_message {
int port;
char name[MAX_NAME_LEN];
char type[MAX_NAME_LEN];
char interface[MAX_IFACE_NAME_LEN];
char iface[MAX_IFACE_NAME_LEN];
} REND_MESSAGE;
#define REND_MSG_TYPE_REGISTER 0

187
src/rend-win32.c Normal file
View File

@ -0,0 +1,187 @@
/*
* $Id$
*
* This is an implementation of rendezvous using the Bonjour (tm)
* for windows dns_sd.h implementation
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include "dns_sd.h"
#include "err.h"
/* Globals */
pthread_t rend_tid;
static volatile int rend_stop_flag = 0;
static volatile int rend_timeout = 10; /* select timeout */
static DNSServiceRef rend_client = NULL;
static DNSServiceRef rend_client2 = NULL;
static volatile int rend_count=0;
/* Forwards */
void *rend_mainthread(void *arg);
void DNSSD_API rend_reg_reply(DNSServiceRef client, const DNSServiceFlags flags,
DNSServiceErrorType errorCode, const char *name,
const char *regtype, const char *domain, void *context);
/* Typedefs */
typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
/**
* initialize the rendezvous interface.
*
* @param user user to drop privs to (ignored)
* @returns 0 on success, -1 with errno set otherwise
*/
int rend_init(char *user) {
/* we'll throw off a handler thread when we register a name */
return 0;
}
/**
* main bonjourvous thread
*
* @param arg unused
*/
void *rend_mainthread(void *arg) {
/* this is pretty much right out of the old mdns stuff */
int dns_sd_fd = rend_client ? DNSServiceRefSockFD(rend_client) : -1;
int dns_sd_fd2 = rend_client2 ? DNSServiceRefSockFD(rend_client2) : -1;
int nfds = dns_sd_fd + 1;
fd_set readfds;
struct timeval tv;
int result;
DNSServiceErrorType err = kDNSServiceErr_NoError;
if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
while (!rend_stop_flag) {
FD_ZERO(&readfds);
if (rend_client) FD_SET(dns_sd_fd, &readfds);
if (rend_client2) FD_SET(dns_sd_fd2, &readfds);
tv.tv_sec = rend_timeout;
tv.tv_usec = 0;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result > 0) {
if (rend_client && FD_ISSET(dns_sd_fd, &readfds)) {
err = DNSServiceProcessResult(rend_client);
} else if (rend_client2 && FD_ISSET(dns_sd_fd2, &readfds)) {
err = DNSServiceProcessResult(rend_client2);
}
if (err) {
DPRINTF(E_LOG,L_REND,"DNSServiceProcessResult returned %d\n", err);
rend_stop_flag = 1;
}
} else if (result == 0) {
DPRINTF(E_DBG,L_REND,"rendezvous: tick!\n");
// myTimerCallBack();
} else {
DPRINTF(E_LOG,L_REND,"select() returned %d errno %d %s\n", result, errno, strerror(errno));
if (errno != EINTR) rend_stop_flag = 1;
}
}
if(rend_client) DNSServiceRefDeallocate(rend_client);
if(rend_client2) DNSServiceRefDeallocate(rend_client2);
rend_client = NULL;
rend_client2 = NULL;
return NULL;
}
/**
* check to see if rendezvous is running.
*
* @returns TRUE if running, FALSE otherwise
*/
int rend_running(void) {
return TRUE;
}
/**
* stop rendezvous if it is running. There should really be a way
* to start it, would't one think?
*
* @returns TRUE if stopped, FALSE otherwise
*/
int rend_stop(void) {
return TRUE;
}
/**
* register a rendezvous name
*
* @param name long name to register (mt-daapd)
* @param type type to register (_daap._tcp)
* @param port port to register (3689)
* @param iface interface to register with (ignored)
* @returns TRUE if registered, FALSE otherwise
*/
int rend_register(char *name, char *type, int port, char *iface) {
int err;
uint16_t port_netorder = htons((unsigned short)port);
DPRINTF(E_INF,L_REND,"Registering %s as type (%s) on port %d\n",
name, type, port);
DNSServiceRegister(&rend_client,0,kDNSServiceInterfaceIndexAny,name,type,"local",NULL,
htons((unsigned short)port),0,NULL,rend_reg_reply, NULL);
/* throw off a new thread work this */
if(!rend_count) {
if((err=pthread_create(&rend_tid,NULL,rend_mainthread,NULL))) {
DPRINTF(E_LOG,L_REND,"Could not spawn thread: %s\n",strerror(err));
errno=err;
return -1;
}
}
rend_count++;
return 0;
}
void DNSSD_API rend_reg_reply(DNSServiceRef client, const DNSServiceFlags flags,
DNSServiceErrorType errorCode, const char *name,
const char *regtype, const char *domain, void *context)
{
DPRINTF(E_INF,L_REND,"Got a reply for %s.%s%s: ", name, regtype, domain);
switch (errorCode) {
case kDNSServiceErr_NoError:
DPRINTF(E_INF,L_REND,"Name now registered and active\n");
break;
case kDNSServiceErr_NameConflict:
DPRINTF(E_FATAL,L_REND,"Rendezvous name in use, aborting...\n");
break;
default:
DPRINTF(E_FATAL,L_REND,"Error %d\n", errorCode);
return;
}
}
/**
* unregister a name
*
* unimplemented
*/
int rend_unregister(char *name, char *type, int port) {
return -1;
}

View File

@ -25,7 +25,7 @@
extern int rend_init(char *user);
extern int rend_running(void);
extern int rend_stop(void);
extern int rend_register(char *name, char *type, int port, char *interface);
extern int rend_register(char *name, char *type, int port, char *iface);
extern int rend_unregister(char *name, char *type, int port);
#endif /* _REND_H_ */

View File

@ -32,40 +32,52 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include "err.h"
#include "restart.h"
#define BLKSIZE PIPE_BUF
#define MILLION 1000000L
#define D_MILLION 1000000.0
/* Private functions */
static int gettimeout(struct timeval end,
struct timeval *timeoutp) {
int gettimeout(struct timeval end,
struct timeval *timeoutp) {
gettimeofday(timeoutp, NULL);
timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec;
timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec;
if (timeoutp->tv_usec >= MILLION) {
timeoutp->tv_sec++;
timeoutp->tv_usec -= MILLION;
timeoutp->tv_sec++;
timeoutp->tv_usec -= MILLION;
}
if (timeoutp->tv_usec < 0) {
timeoutp->tv_sec--;
timeoutp->tv_usec += MILLION;
timeoutp->tv_sec--;
timeoutp->tv_usec += MILLION;
}
if ((timeoutp->tv_sec < 0) ||
((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
errno = ETIME;
return -1;
((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
errno = ETIME;
return -1;
}
return 0;
}
@ -103,28 +115,9 @@ int r_open2(const char *path, int oflag) {
return retval;
}
int r_open3(const char *path, int oflag, mode_t mode) {
int retval;
while (retval = open(path, oflag, mode), retval == -1 && errno == EINTR) ;
return retval;
}
ssize_t r_read(int fd, void *buf, size_t size) {
ssize_t retval;
while (((retval = read(fd, buf, size)) == -1) && (errno==EINTR)) {};
return retval;
}
pid_t r_wait(int *stat_loc) {
pid_t retval;
while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ;
return retval;
}
pid_t r_waitpid(pid_t pid, int *stat_loc, int options) {
pid_t retval;
while (((retval = waitpid(pid, stat_loc, options)) == -1) &&
(errno == EINTR)) ;
while (((retval = read(fd, buf, (int)size)) == -1) && (errno==EINTR)) {};
return retval;
}
@ -135,16 +128,16 @@ ssize_t r_write(int fd, void *buf, size_t size) {
size_t totalbytes;
for (bufp = buf, bytestowrite = size, totalbytes = 0;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if ((byteswritten) == -1 && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if ((byteswritten) == -1 && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
}
return totalbytes;
return (ssize_t) totalbytes;
}
/* Utility functions */
@ -156,8 +149,8 @@ struct timeval add2currenttime(double seconds) {
newtime.tv_sec += (int)seconds;
newtime.tv_usec += (int)((seconds - (int)seconds)*D_MILLION + 0.5);
if (newtime.tv_usec >= MILLION) {
newtime.tv_sec++;
newtime.tv_usec -= MILLION;
newtime.tv_sec++;
newtime.tv_usec -= MILLION;
}
return newtime;
}
@ -167,7 +160,7 @@ int copyfile(int fromfd, int tofd) {
int totalbytes = 0;
while ((bytesread = readwrite(fromfd, tofd)) > 0)
totalbytes += bytesread;
totalbytes += bytesread;
return totalbytes;
}
@ -178,22 +171,22 @@ ssize_t readblock(int fd, void *buf, size_t size) {
size_t totalbytes;
for (bufp = buf, bytestoread = size, totalbytes = 0;
bytestoread > 0;
bufp += bytesread, bytestoread -= bytesread) {
bytesread = read(fd, bufp, bytestoread);
if ((bytesread == 0) && (totalbytes == 0))
return 0;
if (bytesread == 0) {
errno = EINVAL;
return -1;
}
if ((bytesread) == -1 && (errno != EINTR))
return -1;
if (bytesread == -1)
bytesread = 0;
totalbytes += bytesread;
bytestoread > 0;
bufp += bytesread, bytestoread -= bytesread) {
bytesread = read(fd, bufp, bytestoread);
if ((bytesread == 0) && (totalbytes == 0))
return 0;
if (bytesread == 0) {
errno = EINVAL;
return -1;
}
if ((bytesread) == -1 && (errno != EINTR))
return -1;
if (bytesread == -1)
bytesread = 0;
totalbytes += bytesread;
}
return totalbytes;
return (ssize_t) totalbytes;
}
int readline(int fd, char *buf, int nbytes) {
@ -201,20 +194,20 @@ int readline(int fd, char *buf, int nbytes) {
int returnval;
while (numread < nbytes - 1) {
returnval = read(fd, buf + numread, 1);
if ((returnval == -1) && (errno == EINTR))
continue;
if ((returnval == 0) && (numread == 0))
return 0;
if (returnval == 0)
break;
if (returnval == -1)
return -1;
numread++;
if (buf[numread-1] == '\n') {
buf[numread] = '\0';
return numread;
}
returnval = read(fd, buf + numread, 1);
if ((returnval == -1) && (errno == EINTR))
continue;
if ((returnval == 0) && (numread == 0))
return 0;
if (returnval == 0)
break;
if (returnval == -1)
return -1;
numread++;
if (buf[numread-1] == '\n') {
buf[numread] = '\0';
return numread;
}
}
errno = EINVAL;
return -1;
@ -225,20 +218,20 @@ int readlinetimed(int fd, char *buf, int nbytes, double seconds) {
int returnval;
while (numread < nbytes - 1) {
returnval = (int)readtimed(fd, buf + numread, 1, seconds);
if ((returnval == -1) && (errno == EINTR))
continue;
if ((returnval == 0) && (numread == 0))
return 0;
if (returnval == 0)
break;
if (returnval == -1)
return -1;
numread++;
if (buf[numread-1] == '\n') {
buf[numread] = '\0';
return numread;
}
returnval = (int)readtimed(fd, buf + numread, 1, seconds);
if ((returnval == -1) && (errno == EINTR))
continue;
if ((returnval == 0) && (numread == 0))
return 0;
if (returnval == 0)
break;
if (returnval == -1)
return -1;
numread++;
if (buf[numread-1] == '\n') {
buf[numread] = '\0';
return numread;
}
}
errno = EINVAL;
return -1;
@ -249,7 +242,7 @@ ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) {
timedone = add2currenttime(seconds);
if (waitfdtimed(fd, timedone) == -1)
return (ssize_t)(-1);
return (ssize_t)(-1);
return r_read(fd, buf, nbyte);
}
@ -258,11 +251,11 @@ int readwrite(int fromfd, int tofd) {
int bytesread;
if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0)
return -1;
return -1;
if (bytesread == 0)
return 0;
return 0;
if (r_write(tofd, buf, bytesread) < 0)
return -1;
return -1;
return bytesread;
}
@ -271,35 +264,37 @@ int readwriteblock(int fromfd, int tofd, char *buf, int size) {
bytesread = readblock(fromfd, buf, size);
if (bytesread != size) /* can only be 0 or -1 */
return bytesread;
return bytesread;
return r_write(tofd, buf, size);
}
#ifndef WIN32
int waitfdtimed(int fd, struct timeval end) {
fd_set readset;
int retval;
struct timeval timeout;
if ((fd < 0) || (fd >= FD_SETSIZE)) {
errno = EINVAL;
return -1;
errno = EINVAL;
return -1;
}
FD_ZERO(&readset);
FD_SET(fd, &readset);
if (gettimeout(end, &timeout) == -1)
return -1;
return -1;
while (((retval = select(fd+1, &readset, NULL, NULL, &timeout)) == -1)
&& (errno == EINTR)) {
if (gettimeout(end, &timeout) == -1)
return -1;
FD_ZERO(&readset);
FD_SET(fd, &readset);
if (gettimeout(end, &timeout) == -1)
return -1;
FD_ZERO(&readset);
FD_SET(fd, &readset);
}
if (retval == 0) {
errno = ETIME;
return -1;
errno = ETIME;
return -1;
}
if (retval == -1)
return -1;
return -1;
return 0;
}
#endif

View File

@ -32,9 +32,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#ifndef ETIME
@ -47,10 +58,7 @@ int r_fdprintf(int fd, char *fmt, ...);
int r_close(int fildes);
int r_dup2(int fildes, int fildes2);
int r_open2(const char *path, int oflag);
int r_open3(const char *path, int oflag, mode_t mode);
ssize_t r_read(int fd, void *buf, size_t size);
pid_t r_wait(int *stat_loc);
pid_t r_waitpid(pid_t pid, int *stat_loc, int options);
ssize_t r_write(int fd, void *buf, size_t size);
ssize_t readblock(int fd, void *buf, size_t size);
int readline(int fd, char *buf, int nbytes);

View File

@ -2,6 +2,9 @@
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
@ -72,42 +75,42 @@ int rxml_decode_string(char *string) {
src=dst=string;
while(*src) {
if((*src) == '&') {
len = strlen(src);
if((len > 3) && (strncmp(src,"&gt;",4) == 0)) {
*dst++ = '>';
src += 4;
} else if((len > 3) && (strncmp(src,"&lt;",4) == 0)) {
*dst++ = '<';
src += 4;
} else if((len > 4) && (strncmp(src,"&amp;",5) == 0)) {
*dst++ = '&';
src += 5;
} else if((len > 5) && (strncmp(src,"&quot;",6) == 0)) {
*dst++ = '"';
src += 6;
} else if((len > 5) && (strncmp(src,"&apos;",6) == 0)) {
*dst ++ = '\'';
src += 6;
} else {
/* &#xx; */
if(!sscanf((char*)&src[2],"%d;",&cval))
return FALSE;
if((*src) == '&') {
len = (int)strlen(src);
if((len > 3) && (strncmp(src,"&gt;",4) == 0)) {
*dst++ = '>';
src += 4;
} else if((len > 3) && (strncmp(src,"&lt;",4) == 0)) {
*dst++ = '<';
src += 4;
} else if((len > 4) && (strncmp(src,"&amp;",5) == 0)) {
*dst++ = '&';
src += 5;
} else if((len > 5) && (strncmp(src,"&quot;",6) == 0)) {
*dst++ = '"';
src += 6;
} else if((len > 5) && (strncmp(src,"&apos;",6) == 0)) {
*dst ++ = '\'';
src += 6;
} else {
/* &#xx; */
if(!sscanf((char*)&src[2],"%d;",&cval))
return FALSE;
*dst++ = cval;
if(src[3] == ';') {
src += 4;
} else if(src[4] == ';') {
src += 5;
} else if(src[5] == ';') {
src += 6;
} else {
return FALSE;
}
}
} else {
*dst++=*src++;
}
*dst++ = cval;
if(src[3] == ';') {
src += 4;
} else if(src[4] == ';') {
src += 5;
} else if(src[5] == ';') {
src += 6;
} else {
return FALSE;
}
}
} else {
*dst++=*src++;
}
}
*dst = '\0';
@ -123,13 +126,13 @@ int rxml_decode_string(char *string) {
* @param udata opaque data structure to pass to the callback
*/
int rxml_open(RXMLHANDLE *vp, char *file,
RXML_EVTHANDLER handler, void *udata) {
RXML_EVTHANDLER handler, void *udata) {
RXML *pnew;
pnew=(RXML*)malloc(sizeof(RXML));
if(!pnew) {
*vp = NULL;
return FALSE;
*vp = NULL;
return FALSE;
}
memset(pnew,0x0,sizeof(RXML));
@ -142,10 +145,10 @@ int rxml_open(RXMLHANDLE *vp, char *file,
pnew->line = 0;
if(!pnew->fhandle)
RXML_ERROR(pnew,E_RXML_OPEN);
RXML_ERROR(pnew,E_RXML_OPEN);
if(pnew->handler)
pnew->handler(RXML_EVT_OPEN, pnew->udata, pnew->fname);
pnew->handler(RXML_EVT_OPEN, pnew->udata, pnew->fname);
return TRUE;
}
@ -177,31 +180,31 @@ char *rxml_errorstring(RXMLHANDLE vp) {
char *estring=NULL;
if(!ph) {
return "Malloc error";
return "Malloc error";
}
if(ph->estring) free(ph->estring);
len = strlen(rxml_estrings[ph->ecode]) + 16;
len = (int)strlen(rxml_estrings[ph->ecode]) + 16;
if((ph->ecode & 0x80)) {
estring=strerror(ph->stdio_errno);
len += strlen(estring);
estring=strerror(ph->stdio_errno);
len += (int)strlen(estring);
}
ph->estring=(char*)malloc(len);
if(!ph->estring)
return "Double-fault malloc error";
return "Double-fault malloc error";
if((ph->ecode & 0x80)) {
snprintf(ph->estring,len,"%s%s",rxml_estrings[ph->ecode],estring);
snprintf(ph->estring,len,"%s%s",rxml_estrings[ph->ecode],estring);
} else {
if(strncmp(rxml_estrings[ph->ecode],"Parse",5)==0) {
snprintf(ph->estring, len, "%s (Line:%d)",
rxml_estrings[ph->ecode], ph->line);
} else {
snprintf(ph->estring,len, "%s", rxml_estrings[ph->ecode]);
}
if(strncmp(rxml_estrings[ph->ecode],"Parse",5)==0) {
snprintf(ph->estring, len, "%s (Line:%d)",
rxml_estrings[ph->ecode], ph->line);
} else {
snprintf(ph->estring,len, "%s", rxml_estrings[ph->ecode]);
}
}
return ph->estring;
@ -234,94 +237,94 @@ int rxml_parse(RXMLHANDLE vp) {
/* walk through and read row by row */
while(fgets(linebuffer,sizeof(linebuffer),ph->fhandle) != NULL) {
ph->line++;
offset=0;
size=strlen(linebuffer);
in_text=0;
text_offset=0;
while(offset < size) {
switch(linebuffer[offset]) {
case '<':
if(in_tag)
RXML_ERROR(ph, E_RXML_NEST);
ph->line++;
offset=0;
size=(int)strlen(linebuffer);
in_text=0;
text_offset=0;
while(offset < size) {
switch(linebuffer[offset]) {
case '<':
if(in_tag)
RXML_ERROR(ph, E_RXML_NEST);
in_tag=TRUE;
tag_start=offset+1;
tag_end=FALSE;
if(linebuffer[tag_start] == '/') {
tag_end = TRUE;
offset++;
tag_start++;
}
in_tag=TRUE;
tag_start=offset+1;
tag_end=FALSE;
if(linebuffer[tag_start] == '/') {
tag_end = TRUE;
offset++;
tag_start++;
}
offset++;
offset++;
in_text=0;
break;
in_text=0;
break;
case '>':
if(!in_tag)
RXML_ERROR(ph, E_RXML_CLOSE);
case '>':
if(!in_tag)
RXML_ERROR(ph, E_RXML_CLOSE);
in_tag=FALSE;
if((offset - tag_start) > RXML_MAX_TAG)
RXML_ERROR(ph, E_RXML_TAGSIZE);
in_tag=FALSE;
if((offset - tag_start) > RXML_MAX_TAG)
RXML_ERROR(ph, E_RXML_TAGSIZE);
strncpy(tagbuffer,&linebuffer[tag_start],offset-tag_start);
tagbuffer[offset-tag_start] = '\0';
strncpy(tagbuffer,&linebuffer[tag_start],offset-tag_start);
tagbuffer[offset-tag_start] = '\0';
if(tag_end) {
/* send the text before the tag end */
if((ph->handler) && (strlen(textbuffer))) {
if(!rxml_decode_string(textbuffer))
RXML_ERROR(ph,E_RXML_ENTITY);
if(tag_end) {
/* send the text before the tag end */
if((ph->handler) && (strlen(textbuffer))) {
if(!rxml_decode_string(textbuffer))
RXML_ERROR(ph,E_RXML_ENTITY);
ph->handler(RXML_EVT_TEXT,ph->udata,textbuffer);
}
}
ph->handler(RXML_EVT_TEXT,ph->udata,textbuffer);
}
}
in_text=1;
text_offset=0;
textbuffer[0] = '\0';
in_text=1;
text_offset=0;
textbuffer[0] = '\0';
single_tag=0;
if(tagbuffer[strlen(tagbuffer)-1] == '/') {
tagbuffer[strlen(tagbuffer)-1] = '\0';
single_tag=1;
}
single_tag=0;
if(tagbuffer[strlen(tagbuffer)-1] == '/') {
tagbuffer[strlen(tagbuffer)-1] = '\0';
single_tag=1;
}
if(ph->handler)
ph->handler(tag_end ? RXML_EVT_END : RXML_EVT_BEGIN,
ph->udata,tagbuffer);
if(ph->handler)
ph->handler(tag_end ? RXML_EVT_END : RXML_EVT_BEGIN,
ph->udata,tagbuffer);
/* send a follow-up end on a <tag/> - style tag */
if((single_tag) && (ph->handler))
ph->handler(RXML_EVT_END,ph->udata,tagbuffer);
/* send a follow-up end on a <tag/> - style tag */
if((single_tag) && (ph->handler))
ph->handler(RXML_EVT_END,ph->udata,tagbuffer);
offset++;
break;
offset++;
break;
default:
if((in_text) && (text_offset < (sizeof(textbuffer)-1))) {
/* get rid of EOL */
if((linebuffer[offset] != '\r') &&
(linebuffer[offset] != '\n')) {
textbuffer[text_offset] = linebuffer[offset];
text_offset++;
textbuffer[text_offset] = '\x0';
}
} else if (in_text) {
/* should warn of an overflow */
}
offset++;
break;
}
}
default:
if((in_text) && (text_offset < (sizeof(textbuffer)-1))) {
/* get rid of EOL */
if((linebuffer[offset] != '\r') &&
(linebuffer[offset] != '\n')) {
textbuffer[text_offset] = linebuffer[offset];
text_offset++;
textbuffer[text_offset] = '\x0';
}
} else if (in_text) {
/* should warn of an overflow */
}
offset++;
break;
}
}
}
ph->stdio_errno=errno;
if(ferror(ph->fhandle))
RXML_ERROR(ph,E_RXML_READ);
RXML_ERROR(ph,E_RXML_READ);
return TRUE;
}

View File

@ -15,7 +15,7 @@ typedef void* RXMLHANDLE;
typedef void(*RXML_EVTHANDLER)(int,void*,char*);
extern int rxml_open(RXMLHANDLE *handle, char *file,
RXML_EVTHANDLER handler, void* udata);
RXML_EVTHANDLER handler, void* udata);
extern int rxml_close(RXMLHANDLE handle);
extern char *rxml_errorstring(RXMLHANDLE handle);
extern int rxml_parse(RXMLHANDLE handle);

View File

@ -26,7 +26,9 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include "err.h"
#include "mp3-scanner.h"
@ -63,7 +65,7 @@ time_t scan_aac_mac_to_unix_time(int t) {
* @returns offset of the atom, or -1 if unsuccessful
*/
off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
unsigned int *atom_length) {
unsigned int *atom_length) {
long atom_offset;
off_t file_size;
char *cur_p, *end_p;
@ -75,40 +77,40 @@ off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
end_p = atom_path;
while (*end_p != '\0') {
end_p++;
end_p++;
}
atom_name[4] = '\0';
cur_p = atom_path;
while (cur_p != NULL) {
if ((end_p - cur_p) < 4) {
return -1;
}
strncpy(atom_name, cur_p, 4);
atom_offset = scan_aac_findatom(aac_fp, file_size,
atom_name, atom_length);
if (atom_offset == -1) {
return -1;
}
DPRINTF(E_SPAM,L_SCAN,"Found %s atom at off %ld.\n",
atom_name, ftell(aac_fp) - 8);
if ((end_p - cur_p) < 4) {
return -1;
}
strncpy(atom_name, cur_p, 4);
atom_offset = scan_aac_findatom(aac_fp, file_size,
atom_name, atom_length);
if (atom_offset == -1) {
return -1;
}
DPRINTF(E_SPAM,L_SCAN,"Found %s atom at off %ld.\n",
atom_name, ftell(aac_fp) - 8);
cur_p = strchr(cur_p, ':');
if (cur_p != NULL) {
cur_p++;
cur_p = strchr(cur_p, ':');
if (cur_p != NULL) {
cur_p++;
/* FIXME
* Hack to deal with atoms that have extra data in addition
* to having child atoms. This should be dealt in a better fashion
* than this (table with skip offsets or a real mp4 parser.) */
if (!strcmp(atom_name, "meta")) {
fseek(aac_fp, 4, SEEK_CUR);
} else if (!strcmp(atom_name, "stsd")) {
fseek(aac_fp, 8, SEEK_CUR);
} else if (!strcmp(atom_name, "mp4a")) {
fseek(aac_fp, 28, SEEK_CUR);
}
}
/* FIXME
* Hack to deal with atoms that have extra data in addition
* to having child atoms. This should be dealt in a better fashion
* than this (table with skip offsets or a real mp4 parser.) */
if (!strcmp(atom_name, "meta")) {
fseek(aac_fp, 4, SEEK_CUR);
} else if (!strcmp(atom_name, "stsd")) {
fseek(aac_fp, 8, SEEK_CUR);
} else if (!strcmp(atom_name, "mp4a")) {
fseek(aac_fp, 28, SEEK_CUR);
}
}
}
return ftell(aac_fp) - 8;
@ -123,30 +125,30 @@ off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
* @param atom_size this will hold the size of the atom found
*/
long scan_aac_findatom(FILE *fin, long max_offset,
char *which_atom, unsigned int *atom_size) {
char *which_atom, unsigned int *atom_size) {
long current_offset=0;
int size;
char atom[4];
while(current_offset < max_offset) {
if(fread((void*)&size,1,sizeof(int),fin) != sizeof(int))
return -1;
if(fread((void*)&size,1,sizeof(int),fin) != sizeof(int))
return -1;
size=ntohl(size);
size=ntohl(size);
if(size <= 7) /* something not right */
return -1;
if(size <= 7) /* something not right */
return -1;
if(fread(atom,1,4,fin) != 4)
return -1;
if(fread(atom,1,4,fin) != 4)
return -1;
if(strncasecmp(atom,which_atom,4) == 0) {
*atom_size=size;
return current_offset;
}
if(strncasecmp(atom,which_atom,4) == 0) {
*atom_size=size;
return current_offset;
}
fseek(fin,size-8,SEEK_CUR);
current_offset+=size;
fseek(fin,size-8,SEEK_CUR);
current_offset+=size;
}
return -1;
@ -181,8 +183,8 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
if(!(fin=fopen(filename,"rb"))) {
DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading\n",filename);
return FALSE;
DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading\n",filename);
return FALSE;
}
fseek(fin,0,SEEK_END);
@ -192,86 +194,86 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
atom_offset=scan_aac_drilltoatom(fin, "moov:udta:meta:ilst", &atom_length);
if(atom_offset != -1) {
/* found the tag section - need to walk through now */
/* found the tag section - need to walk through now */
while(current_offset < atom_length) {
if(fread((void*)&current_size,1,sizeof(int),fin) != sizeof(int))
break;
current_size=ntohl(current_size);
if(current_size <= 7) /* something not right */
break;
while(current_offset < (long)atom_length) {
if(fread((void*)&current_size,1,sizeof(int),fin) != sizeof(int))
break;
current_size=ntohl(current_size);
if(current_size <= 7) /* something not right */
break;
if(fread(current_atom,1,4,fin) != 4)
break;
len=current_size-7; /* for ill-formed too-short tags */
if(len < 22)
len=22;
if(fread(current_atom,1,4,fin) != 4)
break;
len=current_size-7; /* for ill-formed too-short tags */
if(len < 22)
len=22;
current_data=(char*)malloc(len); /* extra byte */
memset(current_data,0x00,len);
current_data=(char*)malloc(len); /* extra byte */
memset(current_data,0x00,len);
if(fread(current_data,1,current_size-8,fin) != current_size-8)
break;
if(fread(current_data,1,current_size-8,fin) != current_size-8)
break;
if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
pmp3->title=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "ART",4)) {
pmp3->artist=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "alb",4)) {
pmp3->album=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "cmt",4)) {
pmp3->comment=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "wrt",4)) {
pmp3->composer=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "grp",4)) {
pmp3->grouping=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "gen",4)) {
/* can this be a winamp genre??? */
pmp3->genre=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"tmpo",4)) {
us_data=*((unsigned short *)&current_data[16]);
us_data=ntohs(us_data);
pmp3->bpm=us_data;
} else if(!memcmp(current_atom,"trkn",4)) {
us_data=*((unsigned short *)&current_data[18]);
us_data=ntohs(us_data);
if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
pmp3->title=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "ART",4)) {
pmp3->artist=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "alb",4)) {
pmp3->album=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "cmt",4)) {
pmp3->comment=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "wrt",4)) {
pmp3->composer=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "grp",4)) {
pmp3->grouping=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"\xA9" "gen",4)) {
/* can this be a winamp genre??? */
pmp3->genre=strdup((char*)&current_data[16]);
} else if(!memcmp(current_atom,"tmpo",4)) {
us_data=*((unsigned short *)&current_data[16]);
us_data=ntohs(us_data);
pmp3->bpm=us_data;
} else if(!memcmp(current_atom,"trkn",4)) {
us_data=*((unsigned short *)&current_data[18]);
us_data=ntohs(us_data);
pmp3->track=us_data;
pmp3->track=us_data;
us_data=*((unsigned short *)&current_data[20]);
us_data=ntohs(us_data);
us_data=*((unsigned short *)&current_data[20]);
us_data=ntohs(us_data);
pmp3->total_tracks=us_data;
} else if(!memcmp(current_atom,"disk",4)) {
us_data=*((unsigned short *)&current_data[18]);
us_data=ntohs(us_data);
pmp3->total_tracks=us_data;
} else if(!memcmp(current_atom,"disk",4)) {
us_data=*((unsigned short *)&current_data[18]);
us_data=ntohs(us_data);
pmp3->disc=us_data;
pmp3->disc=us_data;
us_data=*((unsigned short *)&current_data[20]);
us_data=ntohs(us_data);
us_data=*((unsigned short *)&current_data[20]);
us_data=ntohs(us_data);
pmp3->total_discs=us_data;
} else if(!memcmp(current_atom,"\xA9" "day",4)) {
pmp3->year=atoi((char*)&current_data[16]);
} else if(!memcmp(current_atom,"gnre",4)) {
genre=(int)(*((char*)&current_data[17]));
genre--;
if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
genre=WINAMP_GENRE_UNKNOWN;
pmp3->total_discs=us_data;
} else if(!memcmp(current_atom,"\xA9" "day",4)) {
pmp3->year=atoi((char*)&current_data[16]);
} else if(!memcmp(current_atom,"gnre",4)) {
genre=(int)(*((char*)&current_data[17]));
genre--;
if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
genre=WINAMP_GENRE_UNKNOWN;
pmp3->genre=strdup(scan_winamp_genre[genre]);
} else if (!memcmp(current_atom, "cpil", 4)) {
pmp3->compilation = current_data[16];
}
pmp3->genre=strdup(scan_winamp_genre[genre]);
} else if (!memcmp(current_atom, "cpil", 4)) {
pmp3->compilation = current_data[16];
}
free(current_data);
current_offset+=current_size;
}
free(current_data);
current_offset+=current_size;
}
}
/* got the tag info, now let's get bitrate, etc */
@ -280,97 +282,97 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
fseek(fin, 4, SEEK_CUR);
fread((void *)&time, sizeof(int), 1, fin);
time = ntohl(time);
pmp3->time_added = scan_aac_mac_to_unix_time(time);
pmp3->time_added = (int)scan_aac_mac_to_unix_time(time);
fread((void *)&time, sizeof(int), 1, fin);
time = ntohl(time);
pmp3->time_modified = scan_aac_mac_to_unix_time(time);
fread((void*)&sample_size,1,sizeof(int),fin);
fread((void*)&samples,1,sizeof(int),fin);
pmp3->time_modified = (int)scan_aac_mac_to_unix_time(time);
fread((void*)&sample_size,1,sizeof(int),fin);
fread((void*)&samples,1,sizeof(int),fin);
sample_size=ntohl(sample_size);
samples=ntohl(samples);
sample_size=ntohl(sample_size);
samples=ntohl(samples);
/* avoid overflowing on large sample_sizes (90000) */
ms=1000;
while((ms > 9) && (!(sample_size % 10))) {
sample_size /= 10;
ms /= 10;
}
/* avoid overflowing on large sample_sizes (90000) */
ms=1000;
while((ms > 9) && (!(sample_size % 10))) {
sample_size /= 10;
ms /= 10;
}
/* DWB: use ms time instead of sec */
pmp3->song_length=(int)((samples * ms) / sample_size);
DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n",
pmp3->song_length / 1000);
/* DWB: use ms time instead of sec */
pmp3->song_length=(int)((samples * ms) / sample_size);
DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n",
pmp3->song_length / 1000);
}
pmp3->bitrate = 0;
/* see if it is aac or alac */
atom_offset = scan_aac_drilltoatom(fin,
"moov:trak:mdia:minf:stbl:stsd:alac",
&atom_length);
"moov:trak:mdia:minf:stbl:stsd:alac",
&atom_length);
if(atom_offset != -1) {
/* should we still pull samplerate, etc from the this atom? */
if(pmp3->codectype) {
free(pmp3->codectype);
}
pmp3->codectype=strdup("alac");
/* should we still pull samplerate, etc from the this atom? */
if(pmp3->codectype) {
free(pmp3->codectype);
}
pmp3->codectype=strdup("alac");
}
/* Get the sample rate from the 'mp4a' atom (timescale). This is also
found in the 'mdhd' atom which is a bit closer but we need to
navigate to the 'mp4a' atom anyways to get to the 'esds' atom. */
atom_offset=scan_aac_drilltoatom(fin,
"moov:trak:mdia:minf:stbl:stsd:mp4a",
&atom_length);
"moov:trak:mdia:minf:stbl:stsd:mp4a",
&atom_length);
if (atom_offset != -1) {
fseek(fin, atom_offset + 32, SEEK_SET);
fseek(fin, atom_offset + 32, SEEK_SET);
/* Timescale here seems to be 2 bytes here (the 2 bytes before it are
* "reserved") though the timescale in the 'mdhd' atom is 4. Not sure
* how this is dealt with when sample rate goes higher than 64K. */
fread(buffer, sizeof(unsigned char), 2, fin);
/* Timescale here seems to be 2 bytes here (the 2 bytes before it are
* "reserved") though the timescale in the 'mdhd' atom is 4. Not sure
* how this is dealt with when sample rate goes higher than 64K. */
fread(buffer, sizeof(unsigned char), 2, fin);
pmp3->samplerate = (buffer[0] << 8) | (buffer[1]);
pmp3->samplerate = (buffer[0] << 8) | (buffer[1]);
/* Seek to end of atom. */
fseek(fin, 2, SEEK_CUR);
/* Seek to end of atom. */
fseek(fin, 2, SEEK_CUR);
/* Get the bit rate from the 'esds' atom. We are already positioned
in the parent atom so just scan ahead. */
atom_offset = scan_aac_findatom(fin,
atom_length-(ftell(fin)-atom_offset),
"esds", &atom_length);
/* Get the bit rate from the 'esds' atom. We are already positioned
in the parent atom so just scan ahead. */
atom_offset = scan_aac_findatom(fin,
atom_length-(ftell(fin)-atom_offset),
"esds", &atom_length);
if (atom_offset != -1) {
/* Roku Soundbridge seems to believe anything above 320K is
* an ALAC encoded m4a. We'll lie on their behalf.
*/
fseek(fin, atom_offset + 22, SEEK_CUR);
fread((void *)&bit_rate, sizeof(unsigned int), 1, fin);
pmp3->bitrate = ntohl(bit_rate) / 1000;
DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);
if (atom_offset != -1) {
/* Roku Soundbridge seems to believe anything above 320K is
* an ALAC encoded m4a. We'll lie on their behalf.
*/
fseek(fin, atom_offset + 22, SEEK_CUR);
fread((void *)&bit_rate, sizeof(unsigned int), 1, fin);
pmp3->bitrate = ntohl(bit_rate) / 1000;
DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);
if(pmp3->bitrate > 320) {
pmp3->bitrate = 320;
}
} else {
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n");
}
if(pmp3->bitrate > 320) {
pmp3->bitrate = 320;
}
} else {
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n");
}
} else {
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n");
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n");
}
/* Fallback if we can't find the info in the atoms. */
if (pmp3->bitrate == 0) {
/* calculate bitrate from song length... Kinda cheesy */
DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n");
atom_offset=scan_aac_drilltoatom(fin,"mdat",&atom_length);
if ((atom_offset != -1) && (pmp3->song_length)) {
pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
}
/* calculate bitrate from song length... Kinda cheesy */
DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n");
atom_offset=scan_aac_drilltoatom(fin,"mdat",&atom_length);
if ((atom_offset != -1) && (pmp3->song_length)) {
pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
}
}
fclose(fin);

View File

@ -49,12 +49,12 @@
#include <FLAC/metadata.h>
#define GET_VORBIS_COMMENT(comment, name, len) (char*) \
#define GET_VORBIS_COMMENT(comment, name, len) (char*) \
(((strncasecmp(name, (char*)(comment).entry, strlen(name)) == 0) && \
((comment).entry[strlen(name)] == '=')) ? \
((*(len) = (comment).length - (strlen(name) + 1)), \
(&((comment).entry[strlen(name) + 1]))) : \
NULL)
((comment).entry[strlen(name)] == '=')) ? \
((*(len) = (comment).length - (strlen(name) + 1)), \
(&((comment).entry[strlen(name) + 1]))) : \
NULL)
/**
* scan a flac file for metainfo.
@ -77,8 +77,8 @@ int scan_get_flacinfo(char *filename, MP3FILE *pmp3) {
/* get file length */
if (!(f = fopen(filename, "rb"))) {
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n", filename);
return FALSE;
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n", filename);
return FALSE;
}
fseek(f, 0, SEEK_END);
pmp3->file_size = ftell(f);
@ -87,103 +87,103 @@ int scan_get_flacinfo(char *filename, MP3FILE *pmp3) {
chain = FLAC__metadata_chain_new();
if (! chain) {
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata chain\n");
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata chain\n");
return FALSE;
}
if (! FLAC__metadata_chain_read(chain, filename)) {
DPRINTF(E_WARN,L_SCAN,"Cannot read FLAC metadata from %s\n", filename);
FLAC__metadata_chain_delete(chain);
return FALSE;
DPRINTF(E_WARN,L_SCAN,"Cannot read FLAC metadata from %s\n", filename);
FLAC__metadata_chain_delete(chain);
return FALSE;
}
iterator = FLAC__metadata_iterator_new();
if (! iterator) {
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata iterator\n");
FLAC__metadata_chain_delete(chain);
return FALSE;
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata iterator\n");
FLAC__metadata_chain_delete(chain);
return FALSE;
}
FLAC__metadata_iterator_init(iterator, chain);
do {
block = FLAC__metadata_iterator_get_block(iterator);
block = FLAC__metadata_iterator_get_block(iterator);
if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
sec = (unsigned int)(block->data.stream_info.total_samples /
block->data.stream_info.sample_rate);
ms = (unsigned int)(((block->data.stream_info.total_samples %
block->data.stream_info.sample_rate) * 1000) /
block->data.stream_info.sample_rate);
if ((sec == 0) && (ms == 0))
break; /* Info is crap, escape div-by-zero. */
pmp3->song_length = (sec * 1000) + ms;
pmp3->bitrate = (pmp3->file_size) / (((sec * 1000) + ms) / 8);
pmp3->samplerate = block->data.stream_info.sample_rate;
if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
sec = (unsigned int)(block->data.stream_info.total_samples /
block->data.stream_info.sample_rate);
ms = (unsigned int)(((block->data.stream_info.total_samples %
block->data.stream_info.sample_rate) * 1000) /
block->data.stream_info.sample_rate);
if ((sec == 0) && (ms == 0))
break; /* Info is crap, escape div-by-zero. */
pmp3->song_length = (sec * 1000) + ms;
pmp3->bitrate = (pmp3->file_size) / (((sec * 1000) + ms) / 8);
pmp3->samplerate = block->data.stream_info.sample_rate;
found |= 1;
if(found == 3)
break;
}
found |= 1;
if(found == 3)
break;
}
if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
for (i = 0; i < block->data.vorbis_comment.num_comments; i++) {
if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"ARTIST", &len))) {
if ((pmp3->artist = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->artist, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"TITLE", &len))) {
if ((pmp3->title = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->title, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"ALBUM", &len))) {
if ((pmp3->album = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->album, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"GENRE", &len))) {
if ((pmp3->genre = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->genre, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"COMPOSER", &len))) {
if ((pmp3->composer = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->composer, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"COMMENT", &len))) {
if ((pmp3->comment = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->comment, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"TRACKNUMBER", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->track = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"DISCNUMBER", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->disc = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"YEAR", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->year = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"DATE", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->year = atoi(val);
*(val + len) = tmp;
}
}
found |= 2;
if(found == 3)
break;
}
if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
for (i = 0; i < block->data.vorbis_comment.num_comments; i++) {
if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"ARTIST", &len))) {
if ((pmp3->artist = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->artist, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"TITLE", &len))) {
if ((pmp3->title = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->title, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"ALBUM", &len))) {
if ((pmp3->album = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->album, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"GENRE", &len))) {
if ((pmp3->genre = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->genre, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"COMPOSER", &len))) {
if ((pmp3->composer = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->composer, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"COMMENT", &len))) {
if ((pmp3->comment = calloc(len + 1, 1)) != NULL)
strncpy(pmp3->comment, val, len);
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"TRACKNUMBER", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->track = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"DISCNUMBER", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->disc = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"YEAR", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->year = atoi(val);
*(val + len) = tmp;
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
"DATE", &len))) {
tmp = *(val + len);
*(val + len) = '\0';
pmp3->year = atoi(val);
*(val + len) = tmp;
}
}
found |= 2;
if(found == 3)
break;
}
} while (FLAC__metadata_iterator_next(iterator));
if (!found) {
DPRINTF(E_WARN,L_SCAN,"Cannot find FLAC metadata in %s\n", filename);
DPRINTF(E_WARN,L_SCAN,"Cannot find FLAC metadata in %s\n", filename);
}
FLAC__metadata_iterator_delete(iterator);

View File

@ -35,6 +35,12 @@
#include "err.h"
#include "mp3-scanner.h"
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
# define _PACKED __attribute((packed))
#else
# define _PACKED
#endif
/**
* Struct to keep info about the information gleaned from
* the mp3 frame header.
@ -59,13 +65,15 @@ typedef struct tag_scan_frameinfo {
int is_valid;
} SCAN_FRAMEINFO;
/* This should take take of win32 and gcc, any others? */
#pragma pack(1)
typedef struct tag_scan_id3header {
unsigned char id[3];
unsigned char version[2];
unsigned char flags;
unsigned char size[4];
} __attribute((packed)) SCAN_ID3HEADER;
} _PACKED SCAN_ID3HEADER;
#pragma pack()
/*
* Globals
@ -342,7 +350,6 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
} else {
utf8_text=(char *)id3_ucs4_utf8duplicate(native_text);
}
MEMNOTIFY(utf8_text);
if(!strcmp(pid3frame->id,"TIT2")) { /* Title */
used=1;
@ -462,7 +469,6 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
utf8_text=(char*)id3_ucs4_utf8duplicate(native_text);
if(utf8_text) {
pmp3->comment=utf8_text;
MEMNOTIFY(pmp3->comment);
}
}
} else {

View File

@ -26,7 +26,9 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include "err.h"
#include "mp3-scanner.h"
@ -84,7 +86,7 @@ int scan_get_mp4info(char *filename, MP3FILE *pmp3) {
if(atom_offset != -1) {
/* found the tag section - need to walk through now */
while(current_offset < atom_length) {
while(current_offset < (long) atom_length) {
if(fread((void*)&current_size,1,sizeof(int),fin) != sizeof(int))
break;
@ -170,11 +172,11 @@ int scan_get_mp4info(char *filename, MP3FILE *pmp3) {
fseek(fin, 4, SEEK_CUR);
fread((void *)&time, sizeof(int), 1, fin);
time = ntohl(time);
pmp3->time_added = scan_aac_mac_to_unix_time(time);
pmp3->time_added = (int) scan_aac_mac_to_unix_time(time);
fread((void *)&time, sizeof(int), 1, fin);
time = ntohl(time);
pmp3->time_modified = scan_aac_mac_to_unix_time(time);
pmp3->time_modified = (int) scan_aac_mac_to_unix_time(time);
fread((void*)&sample_size,1,sizeof(int),fin);
fread((void*)&samples,1,sizeof(int),fin);

View File

@ -33,61 +33,61 @@ int scan_get_ogginfo(char *filename, MP3FILE *pmp3) {
f = fopen(filename, "rb");
if (f == NULL) {
DPRINTF(E_FATAL, L_SCAN,
"Error opening input file \"%s\": %s\n", filename,
strerror(errno));
"Error opening input file \"%s\": %s\n", filename,
strerror(errno));
return FALSE;
}
if(!fseek(f,0,SEEK_END)) {
pmp3->file_size=ftell(f);
fseek(f,0,SEEK_SET);
pmp3->file_size=ftell(f);
fseek(f,0,SEEK_SET);
}
if (ov_open(f, &vf, NULL, 0) != 0) {
fclose(f);
fclose(f);
DPRINTF(E_FATAL, L_SCAN,
"Error opening Vorbis stream in \"%s\"\n", filename);
"Error opening Vorbis stream in \"%s\"\n", filename);
return FALSE;
}
vi=ov_info(&vf,-1);
if(vi) {
DPRINTF(E_DBG,L_SCAN," Bitrates: %d %d %d\n",vi->bitrate_upper,
vi->bitrate_nominal,vi->bitrate_lower);
if(vi->bitrate_nominal) {
pmp3->bitrate=vi->bitrate_nominal / 1000;
} else if(vi->bitrate_upper) {
pmp3->bitrate=vi->bitrate_upper / 1000;
} else if(vi->bitrate_lower) {
pmp3->bitrate=vi->bitrate_lower / 1000;
}
DPRINTF(E_DBG,L_SCAN," Bitrates: %d %d %d\n",vi->bitrate_upper,
vi->bitrate_nominal,vi->bitrate_lower);
if(vi->bitrate_nominal) {
pmp3->bitrate=vi->bitrate_nominal / 1000;
} else if(vi->bitrate_upper) {
pmp3->bitrate=vi->bitrate_upper / 1000;
} else if(vi->bitrate_lower) {
pmp3->bitrate=vi->bitrate_lower / 1000;
}
DPRINTF(E_DBG,L_SCAN," Bitrates: %d",pmp3->bitrate);
pmp3->samplerate=vi->rate;
DPRINTF(E_DBG,L_SCAN," Bitrates: %d",pmp3->bitrate);
pmp3->samplerate=vi->rate;
}
pmp3->song_length=ov_time_total(&vf,-1) * 1000;
comment = ov_comment(&vf, -1);
if (comment != NULL) {
if ((val = vorbis_comment_query(comment, "artist", 0)) != NULL)
pmp3->artist = strdup(val);
if ((val = vorbis_comment_query(comment, "title", 0)) != NULL)
pmp3->title = strdup(val);
if ((val = vorbis_comment_query(comment, "album", 0)) != NULL)
pmp3->album = strdup(val);
if ((val = vorbis_comment_query(comment, "genre", 0)) != NULL)
pmp3->genre = strdup(val);
if ((val = vorbis_comment_query(comment, "composer", 0)) != NULL)
pmp3->composer = strdup(val);
if ((val = vorbis_comment_query(comment, "comment", 0)) != NULL)
pmp3->comment = strdup(val);
if ((val = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
pmp3->track = atoi(val);
if ((val = vorbis_comment_query(comment, "discnumber", 0)) != NULL)
pmp3->disc = atoi(val);
if ((val = vorbis_comment_query(comment, "year", 0)) != NULL)
pmp3->year = atoi(val);
if ((val = vorbis_comment_query(comment, "artist", 0)) != NULL)
pmp3->artist = strdup(val);
if ((val = vorbis_comment_query(comment, "title", 0)) != NULL)
pmp3->title = strdup(val);
if ((val = vorbis_comment_query(comment, "album", 0)) != NULL)
pmp3->album = strdup(val);
if ((val = vorbis_comment_query(comment, "genre", 0)) != NULL)
pmp3->genre = strdup(val);
if ((val = vorbis_comment_query(comment, "composer", 0)) != NULL)
pmp3->composer = strdup(val);
if ((val = vorbis_comment_query(comment, "comment", 0)) != NULL)
pmp3->comment = strdup(val);
if ((val = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
pmp3->track = atoi(val);
if ((val = vorbis_comment_query(comment, "discnumber", 0)) != NULL)
pmp3->disc = atoi(val);
if ((val = vorbis_comment_query(comment, "year", 0)) != NULL)
pmp3->year = atoi(val);
}
ov_clear(&vf);
/*fclose(f);*/

View File

@ -47,31 +47,31 @@ int scan_get_urlinfo(char *filename, MP3FILE *pmp3) {
DPRINTF(E_DBG,L_SCAN,"Getting URL file info\n");
if(!(infile=fopen(filename,"rb"))) {
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
return FALSE;
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
return FALSE;
}
fgets(linebuffer,sizeof(linebuffer),infile);
while((linebuffer[strlen(linebuffer)-1] == '\n') ||
(linebuffer[strlen(linebuffer)-1] == '\r')) {
linebuffer[strlen(linebuffer)-1] = '\0';
(linebuffer[strlen(linebuffer)-1] == '\r')) {
linebuffer[strlen(linebuffer)-1] = '\0';
}
head=linebuffer;
tail=strchr(head,',');
if(!tail) {
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
fclose(infile);
return FALSE;
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
fclose(infile);
return FALSE;
}
pmp3->bitrate=atoi(head);
head=++tail;
tail=strchr(head,',');
if(!tail) {
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
fclose(infile);
return FALSE;
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
fclose(infile);
return FALSE;
}
*tail++='\0';

View File

@ -30,13 +30,13 @@
#include "err.h"
#include "mp3-scanner.h"
#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \
(((unsigned long)((p)[2])) << 16) | \
(((unsigned long)((p)[1])) << 8) | \
(((unsigned long)((p)[0]))))
#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \
(((unsigned long)((p)[2])) << 16) | \
(((unsigned long)((p)[1])) << 8) | \
(((unsigned long)((p)[0]))))
#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \
(((unsigned long)((p)[0]))))
#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \
(((unsigned long)((p)[0]))))
/**
* Get info from the actual wav headers. Since there is no
@ -64,8 +64,8 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
DPRINTF(E_DBG,L_SCAN,"Getting WAV file info\n");
if(!(infile=fopen(filename,"rb"))) {
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
return FALSE;
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
return FALSE;
}
fseek(infile,0,SEEK_END);
@ -75,15 +75,15 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
rl = fread(hdr, 1, 44, infile);
fclose(infile);
if (rl != 44) {
DPRINTF(E_WARN,L_SCAN,"Could not read wav header from %s\n",filename);
DPRINTF(E_WARN,L_SCAN,"Could not read wav header from %s\n",filename);
return FALSE;
}
if (strncmp((char*)hdr + 0, "RIFF", 4) ||
strncmp((char*)hdr + 8, "WAVE", 4) ||
strncmp((char*)hdr + 12, "fmt ", 4) ||
strncmp((char*)hdr + 36, "data", 4)) {
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
strncmp((char*)hdr + 8, "WAVE", 4) ||
strncmp((char*)hdr + 12, "fmt ", 4) ||
strncmp((char*)hdr + 36, "data", 4)) {
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
return FALSE;
}
@ -96,9 +96,9 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
data_length = GET_WAV_INT32(hdr + 40);
if ((format_data_length != 16) ||
(compression_code != 1) ||
(channel_count < 1)) {
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
(compression_code != 1) ||
(channel_count < 1)) {
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
return FALSE;
}

View File

@ -221,22 +221,28 @@ WMA_GUID wma_guidlist[] = {
{ NULL, NULL, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" }
};
#define PACKED __attribute__((packed))
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
# define _PACKED __attribute((packed))
#else
# define _PACKED
#endif
#define MAYBEFREE(x) { free((x)); }
#pragma pack(1)
typedef struct tag_wma_header {
unsigned char objectid[16];
unsigned long long size;
unsigned int objects;
char reserved1;
char reserved2;
} PACKED WMA_HEADER;
} _PACKED WMA_HEADER;
typedef struct tag_wma_subheader {
unsigned char objectid[16];
long long size;
} PACKED WMA_SUBHEADER;
} _PACKED WMA_SUBHEADER;
#pragma pack()
/*
* Forwards
@ -256,7 +262,7 @@ int wma_parse_file_properteis(int fd,int size, MP3FILE *pmp3);
*/
int wma_file_read_short(int fd, unsigned short int *psi) {
if(r_read(fd,(void*)psi,sizeof(unsigned short int)) != sizeof(unsigned short int)) {
return 0;
return 0;
}
*psi = wma_convert_short((unsigned char *)psi);
@ -268,7 +274,7 @@ int wma_file_read_short(int fd, unsigned short int *psi) {
*/
int wma_file_read_int(int fd, unsigned int *pi) {
if(r_read(fd,(void*)pi,sizeof(unsigned int)) != sizeof(unsigned int)) {
return 0;
return 0;
}
*pi = wma_convert_int((unsigned char *)pi);
@ -280,7 +286,7 @@ int wma_file_read_int(int fd, unsigned int *pi) {
*/
int wma_file_read_ll(int fd, unsigned long long *pll) {
if(r_read(fd,(void*)pll,sizeof(unsigned long long)) != sizeof(unsigned long long)) {
return 0;
return 0;
}
*pll = wma_convert_ll((unsigned char *)pll);
@ -296,10 +302,10 @@ int wma_file_read_utf16(int fd, int len, char **utf8) {
utf16=(unsigned char*)malloc(len);
if(!utf16)
return 0;
return 0;
if(r_read(fd,utf16,len) != len)
return 0;
return 0;
out = wma_utf16toutf8(utf16,len);
*utf8 = out;
@ -311,10 +317,10 @@ int wma_file_read_utf16(int fd, int len, char **utf8) {
int wma_file_read_bytes(int fd,int len, unsigned char **data) {
*data = (unsigned char *)malloc(len);
if(!*data)
return 0;
return 0;
if(r_read(fd,*data,len) != len)
return 0;
return 0;
return 1;
}
@ -344,98 +350,98 @@ int wma_parse_extended_content_description(int fd,int size, MP3FILE *pmp3) {
DPRINTF(E_DBG,L_SCAN,"Reading extended content description object\n");
if(!wma_file_read_short(fd, &descriptor_count))
return FALSE;
return FALSE;
for(index = 0; index < descriptor_count; index++) {
if(!wma_file_read_short(fd,&descriptor_name_len)) return -1;
if(!wma_file_read_utf16(fd,descriptor_name_len,&descriptor_name)) return -1;
if(!wma_file_read_short(fd,&descriptor_value_type)) {
free(descriptor_name);
return FALSE;
}
if(!wma_file_read_short(fd,&descriptor_value_len)) {
free(descriptor_name);
return FALSE;
}
if(!wma_file_read_short(fd,&descriptor_name_len)) return -1;
if(!wma_file_read_utf16(fd,descriptor_name_len,&descriptor_name)) return -1;
if(!wma_file_read_short(fd,&descriptor_value_type)) {
free(descriptor_name);
return FALSE;
}
if(!wma_file_read_short(fd,&descriptor_value_len)) {
free(descriptor_name);
return FALSE;
}
DPRINTF(E_DBG,L_SCAN,"Found descriptor: %s\n", descriptor_name);
DPRINTF(E_DBG,L_SCAN,"Found descriptor: %s\n", descriptor_name);
/* see what kind it is */
switch(descriptor_value_type) {
case 0x0000: /* string */
if(!wma_file_read_utf16(fd,descriptor_value_len,
&descriptor_byte_value)) {
fail=1;
}
DPRINTF(E_DBG,L_SCAN,"Type: string, value: %s\n",descriptor_byte_value);
break;
case 0x0001: /* byte array */
if(!wma_file_read_bytes(fd,descriptor_value_len,
(unsigned char **)&descriptor_byte_value)){
fail=1;
}
DPRINTF(E_DBG,L_SCAN,"Type: bytes\n");
break;
case 0x0002: /* bool - dropthru */
case 0x0003: /* dword */
if(!wma_file_read_int(fd,&descriptor_int_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"Type: int, value: %d\n",descriptor_int_value);
break;
case 0x0004: /* qword */
if(!wma_file_read_ll(fd,&descriptor_ll_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"Type: ll, value: %lld\n",descriptor_ll_value);
break;
case 0x0005: /* word */
if(!wma_file_read_short(fd,&descriptor_short_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"type: short, value %d\n",descriptor_short_value);
break;
}
/* see what kind it is */
switch(descriptor_value_type) {
case 0x0000: /* string */
if(!wma_file_read_utf16(fd,descriptor_value_len,
&descriptor_byte_value)) {
fail=1;
}
DPRINTF(E_DBG,L_SCAN,"Type: string, value: %s\n",descriptor_byte_value);
break;
case 0x0001: /* byte array */
if(!wma_file_read_bytes(fd,descriptor_value_len,
(unsigned char **)&descriptor_byte_value)){
fail=1;
}
DPRINTF(E_DBG,L_SCAN,"Type: bytes\n");
break;
case 0x0002: /* bool - dropthru */
case 0x0003: /* dword */
if(!wma_file_read_int(fd,&descriptor_int_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"Type: int, value: %d\n",descriptor_int_value);
break;
case 0x0004: /* qword */
if(!wma_file_read_ll(fd,&descriptor_ll_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"Type: ll, value: %lld\n",descriptor_ll_value);
break;
case 0x0005: /* word */
if(!wma_file_read_short(fd,&descriptor_short_value)) fail=1;
DPRINTF(E_DBG,L_SCAN,"type: short, value %d\n",descriptor_short_value);
break;
}
if(fail) {
free(descriptor_name);
return FALSE;
}
if(fail) {
free(descriptor_name);
return FALSE;
}
/* do stuff with what we found */
if(strcasecmp(descriptor_name,"wm/genre")==0) {
MAYBEFREE(pmp3->genre);
pmp3->genre = descriptor_byte_value;
descriptor_byte_value = NULL; /* don't free it! */
} else if(strcasecmp(descriptor_name,"wm/albumtitle")==0) {
MAYBEFREE(pmp3->album);
pmp3->album = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/track")==0) {
pmp3->track = descriptor_int_value + 1;
} else if(strcasecmp(descriptor_name,"wm/tracknumber")==0) {
pmp3->track = descriptor_int_value;
} else if(strcasecmp(descriptor_name,"wm/year")==0) {
pmp3->year = atoi(descriptor_byte_value);
} else if(strcasecmp(descriptor_name,"wm/composer")==0) {
MAYBEFREE(pmp3->composer);
pmp3->composer = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/albumartist")==0) {
MAYBEFREE(pmp3->artist);
pmp3->artist = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/contengroupdescription")==0) {
MAYBEFREE(pmp3->grouping);
pmp3->grouping = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"comment")==0) {
MAYBEFREE(pmp3->comment);
pmp3->comment = descriptor_byte_value;
descriptor_byte_value = NULL;
}
/* do stuff with what we found */
if(strcasecmp(descriptor_name,"wm/genre")==0) {
MAYBEFREE(pmp3->genre);
pmp3->genre = descriptor_byte_value;
descriptor_byte_value = NULL; /* don't free it! */
} else if(strcasecmp(descriptor_name,"wm/albumtitle")==0) {
MAYBEFREE(pmp3->album);
pmp3->album = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/track")==0) {
pmp3->track = descriptor_int_value + 1;
} else if(strcasecmp(descriptor_name,"wm/tracknumber")==0) {
pmp3->track = descriptor_int_value;
} else if(strcasecmp(descriptor_name,"wm/year")==0) {
pmp3->year = atoi(descriptor_byte_value);
} else if(strcasecmp(descriptor_name,"wm/composer")==0) {
MAYBEFREE(pmp3->composer);
pmp3->composer = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/albumartist")==0) {
MAYBEFREE(pmp3->artist);
pmp3->artist = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"wm/contengroupdescription")==0) {
MAYBEFREE(pmp3->grouping);
pmp3->grouping = descriptor_byte_value;
descriptor_byte_value = NULL;
} else if(strcasecmp(descriptor_name,"comment")==0) {
MAYBEFREE(pmp3->comment);
pmp3->comment = descriptor_byte_value;
descriptor_byte_value = NULL;
}
/* cleanup - done with this round */
if(descriptor_byte_value) {
free(descriptor_byte_value);
descriptor_byte_value = NULL;
}
/* cleanup - done with this round */
if(descriptor_byte_value) {
free(descriptor_byte_value);
descriptor_byte_value = NULL;
}
free(descriptor_name);
free(descriptor_name);
}
return TRUE;
@ -456,47 +462,47 @@ int wma_parse_content_description(int fd,int size, MP3FILE *pmp3) {
char *utf8;
if(size < 10) /* must be at least enough room for the size block */
return FALSE;
return FALSE;
for(index=0; index < 5; index++) {
if(!wma_file_read_short(fd,&sizes[index]))
return FALSE;
if(!wma_file_read_short(fd,&sizes[index]))
return FALSE;
}
for(index=0;index<5;index++) {
if(sizes[index]) {
if(!wma_file_read_utf16(fd,sizes[index],&utf8))
return FALSE;
if(sizes[index]) {
if(!wma_file_read_utf16(fd,sizes[index],&utf8))
return FALSE;
DPRINTF(E_DBG,L_SCAN,"Got item of length %d: %s\n",sizes[index],utf8);
switch(index) {
case 0: /* title */
if(pmp3->title)
free(pmp3->title);
pmp3->title = utf8;
break;
case 1: /* author */
if(pmp3->artist)
free(pmp3->artist);
pmp3->artist = utf8;
break;
case 2: /* copyright - dontcare */
free(utf8);
break;
case 3: /* description */
if(pmp3->comment)
free(pmp3->comment);
pmp3->comment = utf8;
break;
case 4: /* rating - dontcare */
free(utf8);
break;
default: /* can't get here */
DPRINTF(E_FATAL,L_SCAN,"This is not my beautiful wife.\n");
break;
}
}
DPRINTF(E_DBG,L_SCAN,"Got item of length %d: %s\n",sizes[index],utf8);
switch(index) {
case 0: /* title */
if(pmp3->title)
free(pmp3->title);
pmp3->title = utf8;
break;
case 1: /* author */
if(pmp3->artist)
free(pmp3->artist);
pmp3->artist = utf8;
break;
case 2: /* copyright - dontcare */
free(utf8);
break;
case 3: /* description */
if(pmp3->comment)
free(pmp3->comment);
pmp3->comment = utf8;
break;
case 4: /* rating - dontcare */
free(utf8);
break;
default: /* can't get here */
DPRINTF(E_FATAL,L_SCAN,"This is not my beautiful wife.\n");
break;
}
}
}
return TRUE;
@ -523,19 +529,19 @@ int wma_parse_file_properties(int fd,int size, MP3FILE *pmp3) {
lseek(fd,40,SEEK_CUR);
if(!wma_file_read_ll(fd, &play_duration))
return FALSE;
return FALSE;
if(!wma_file_read_ll(fd, &send_duration))
return FALSE;
return FALSE;
if(!wma_file_read_ll(fd, &preroll))
return FALSE;
return FALSE;
/* I'm not entirely certain what preroll is, but it seems
* to make it match up with what windows thinks is the song
* length.
*/
pmp3->song_length = ((int) (play_duration / 10000)) - preroll;
pmp3->song_length = ((int)play_duration / 10000) - (int)preroll;
/* skip flags(4),
* min_packet_size (4), max_packet_size(4)
@ -543,7 +549,7 @@ int wma_parse_file_properties(int fd,int size, MP3FILE *pmp3) {
lseek(fd,12,SEEK_CUR);
if(!wma_file_read_int(fd,&max_bitrate))
return FALSE;
return FALSE;
pmp3->bitrate = max_bitrate/1000;
@ -573,59 +579,59 @@ char *wma_utf16toutf8(unsigned char *utf16, int len) {
int bytes;
if(!len)
return NULL;
return NULL;
utf8=(char *)malloc(len*2 + 1);
if(!utf8)
return NULL;
return NULL;
memset(utf8,0x0,len*2 + 1);
dst=utf8;
while((src+2) <= utf16+len) {
w1=src[1] << 8 | src[0];
src += 2;
if((w1 & 0xFC00) == 0xD800) { /* could be surrogate pair */
if(src+2 > utf16+len) {
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
free(utf8);
return NULL;
}
w2 = src[3] << 8 | src[2];
if((w2 & 0xFC00) != 0xDC00) {
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
free(utf8);
return NULL;
}
w1=src[1] << 8 | src[0];
src += 2;
if((w1 & 0xFC00) == 0xD800) { /* could be surrogate pair */
if(src+2 > utf16+len) {
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
free(utf8);
return NULL;
}
w2 = src[3] << 8 | src[2];
if((w2 & 0xFC00) != 0xDC00) {
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
free(utf8);
return NULL;
}
/* get bottom 10 of each */
w1 = w1 & 0x03FF;
w1 = w1 << 10;
w1 = w1 | (w2 & 0x03FF);
/* get bottom 10 of each */
w1 = w1 & 0x03FF;
w1 = w1 << 10;
w1 = w1 | (w2 & 0x03FF);
/* add back the 0x10000 */
w1 += 0x10000;
}
/* add back the 0x10000 */
w1 += 0x10000;
}
/* now encode the original code point in utf-8 */
if (w1 < 0x80) {
*dst++ = w1;
bytes=0;
} else if (w1 < 0x800) {
*dst++ = 0xC0 | (w1 >> 6);
bytes=1;
} else if (w1 < 0x10000) {
*dst++ = 0xE0 | (w1 >> 12);
bytes=2;
} else {
*dst++ = 0xF0 | (w1 >> 18);
bytes=3;
}
/* now encode the original code point in utf-8 */
if (w1 < 0x80) {
*dst++ = w1;
bytes=0;
} else if (w1 < 0x800) {
*dst++ = 0xC0 | (w1 >> 6);
bytes=1;
} else if (w1 < 0x10000) {
*dst++ = 0xE0 | (w1 >> 12);
bytes=2;
} else {
*dst++ = 0xF0 | (w1 >> 18);
bytes=3;
}
while(bytes) {
*dst++ = 0x80 | ((w1 >> (6*bytes)) & 0x3f);
bytes--;
}
while(bytes) {
*dst++ = 0x80 | ((w1 >> (6*bytes)) & 0x3f);
bytes--;
}
}
return utf8;
@ -640,11 +646,11 @@ WMA_GUID *wma_find_guid(unsigned char *guid) {
WMA_GUID *pguid = wma_guidlist;
while((pguid->name) && (memcmp(guid,pguid->value,16) != 0)) {
pguid++;
pguid++;
}
if(!pguid->name)
return NULL;
return NULL;
return pguid;
}
@ -656,7 +662,7 @@ WMA_GUID *wma_find_guid(unsigned char *guid) {
*/
unsigned short wma_convert_short(unsigned char *src) {
return src[1] << 8 |
src[0];
src[0];
}
/**
@ -666,9 +672,9 @@ unsigned short wma_convert_short(unsigned char *src) {
*/
unsigned int wma_convert_int(unsigned char *src) {
return src[3] << 24 |
src[2] << 16 |
src[1] << 8 |
src[0];
src[2] << 16 |
src[1] << 8 |
src[0];
}
/**
@ -682,14 +688,14 @@ unsigned long long wma_convert_ll(unsigned char *src) {
unsigned long long retval;
tmp_hi = src[7] << 24 |
src[6] << 16 |
src[5] << 8 |
src[4];
src[6] << 16 |
src[5] << 8 |
src[4];
tmp_lo = src[3] << 24 |
src[2] << 16 |
src[1] << 8 |
src[0];
src[2] << 16 |
src[1] << 8 |
src[0];
retval = tmp_hi;
retval = (retval << 32) | tmp_lo;
@ -715,23 +721,23 @@ int scan_get_wmainfo(char *filename, MP3FILE *pmp3) {
wma_fd = r_open2(filename,O_RDONLY);
if(wma_fd == -1) {
DPRINTF(E_INF,L_SCAN,"Error opening WMA file (%s): %s\n",filename,
strerror(errno));
return FALSE;
DPRINTF(E_INF,L_SCAN,"Error opening WMA file (%s): %s\n",filename,
strerror(errno));
return FALSE;
}
if(read(wma_fd,(void*)&hdr,sizeof(hdr)) != sizeof(hdr)) {
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
strerror(errno));
r_close(wma_fd);
return FALSE;
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
strerror(errno));
r_close(wma_fd);
return FALSE;
}
pguid = wma_find_guid(hdr.objectid);
if(!pguid) {
DPRINTF(E_INF,L_SCAN,"Could not find header in %s\n",filename);
r_close(wma_fd);
return FALSE;
DPRINTF(E_INF,L_SCAN,"Could not find header in %s\n",filename);
r_close(wma_fd);
return FALSE;
}
hdr.objects=wma_convert_int((unsigned char *)&hdr.objects);
@ -747,56 +753,56 @@ int scan_get_wmainfo(char *filename, MP3FILE *pmp3) {
* find anything interesting
*/
for(item=0; item < hdr.objects; item++) {
if(lseek(wma_fd,offset,SEEK_SET) == (off_t)-1) {
DPRINTF(E_INF,L_SCAN,"Error seeking in %s\n",filename);
r_close(wma_fd);
return FALSE;
}
for(item=0; item < (int) hdr.objects; item++) {
if(lseek(wma_fd,offset,SEEK_SET) == (off_t)-1) {
DPRINTF(E_INF,L_SCAN,"Error seeking in %s\n",filename);
r_close(wma_fd);
return FALSE;
}
if(r_read(wma_fd,(void*)&subhdr,sizeof(subhdr)) != sizeof(subhdr)) {
err=errno;
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
strerror(err));
r_close(wma_fd);
return FALSE;
}
if(r_read(wma_fd,(void*)&subhdr,sizeof(subhdr)) != sizeof(subhdr)) {
err=errno;
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
strerror(err));
r_close(wma_fd);
return FALSE;
}
subhdr.size=wma_convert_ll((unsigned char *)&subhdr.size);
subhdr.size=wma_convert_ll((unsigned char *)&subhdr.size);
pguid = wma_find_guid(subhdr.objectid);
if(pguid) {
DPRINTF(E_DBG,L_SCAN,"Found subheader: %s\n",pguid->name);
if(strcmp(pguid->name,"ASF_Content_Description_Object")==0) {
res &= wma_parse_content_description(wma_fd,subhdr.size,pmp3);
} else if (strcmp(pguid->name,"ASF_Extended_Content_Description_Object")==0) {
res &= wma_parse_extended_content_description(wma_fd,subhdr.size,pmp3);
} else if (strcmp(pguid->name,"ASF_File_Properties_Object")==0) {
res &= wma_parse_file_properties(wma_fd,subhdr.size,pmp3);
}
} else {
DPRINTF(E_DBG,L_SCAN,"Unknown subheader: %02hhx%02hhx%02hhx%02hhx-"
"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
subhdr.objectid[3],subhdr.objectid[2],
subhdr.objectid[1],subhdr.objectid[0],
subhdr.objectid[5],subhdr.objectid[4],
subhdr.objectid[7],subhdr.objectid[6],
subhdr.objectid[8],subhdr.objectid[9],
subhdr.objectid[10],subhdr.objectid[11],
subhdr.objectid[12],subhdr.objectid[13],
subhdr.objectid[14],subhdr.objectid[15]);
pguid = wma_find_guid(subhdr.objectid);
if(pguid) {
DPRINTF(E_DBG,L_SCAN,"Found subheader: %s\n",pguid->name);
if(strcmp(pguid->name,"ASF_Content_Description_Object")==0) {
res &= wma_parse_content_description(wma_fd,(int)subhdr.size,pmp3);
} else if (strcmp(pguid->name,"ASF_Extended_Content_Description_Object")==0) {
res &= wma_parse_extended_content_description(wma_fd,(int)subhdr.size,pmp3);
} else if (strcmp(pguid->name,"ASF_File_Properties_Object")==0) {
res &= wma_parse_file_properties(wma_fd,(int)subhdr.size,pmp3);
}
} else {
DPRINTF(E_DBG,L_SCAN,"Unknown subheader: %02hhx%02hhx%02hhx%02hhx-"
"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
subhdr.objectid[3],subhdr.objectid[2],
subhdr.objectid[1],subhdr.objectid[0],
subhdr.objectid[5],subhdr.objectid[4],
subhdr.objectid[7],subhdr.objectid[6],
subhdr.objectid[8],subhdr.objectid[9],
subhdr.objectid[10],subhdr.objectid[11],
subhdr.objectid[12],subhdr.objectid[13],
subhdr.objectid[14],subhdr.objectid[15]);
}
offset += subhdr.size;
}
offset += (long) subhdr.size;
}
if(!res) {
DPRINTF(E_INF,L_SCAN,"Error reading meta info for file %s\n",
filename);
DPRINTF(E_INF,L_SCAN,"Error reading meta info for file %s\n",
filename);
} else {
DPRINTF(E_DBG,L_SCAN,"Successfully parsed file\n");
DPRINTF(E_DBG,L_SCAN,"Successfully parsed file\n");
}
r_close(wma_fd);

View File

@ -37,6 +37,7 @@
#include "mp3-scanner.h"
#include "rxml.h"
#include "redblack.h"
#include "strptime.h"
/* Forwards */
int scan_xml_playlist(char *filename);
@ -126,7 +127,7 @@ int scan_xml_datedecode(char *string) {
strptime(string,"%Y-%m-%dT%H:%M:%SZ",&date_time);
seconds = timegm(&date_time);
return seconds;
return (int)seconds;
}
/**
@ -204,7 +205,7 @@ int scan_xml_translate_path(char *pold, char *pnew) {
DPRINTF(E_DBG,L_SCAN,"Trying %s\n",base_path);
if(scan_xml_is_file(base_path)) {
path_found=1;
discard = (current - working_path);
discard = (int)(current - working_path);
DPRINTF(E_DBG,L_SCAN,"Found it!\n");
}
*current='\0';

View File

@ -140,28 +140,28 @@ int main(int argc, char *argv[]) {
memset((void*)&mp3,0x00,sizeof(MP3FILE));
if(strchr(argv[0],'/')) {
av0 = strrchr(argv[0],'/')+1;
av0 = strrchr(argv[0],'/')+1;
} else {
av0 = argv[0];
av0 = argv[0];
}
while((option = getopt(argc, argv, "d:")) != -1) {
switch(option) {
case 'd':
err_debuglevel = atoi(optarg);
break;
default:
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
usage(-1);
}
switch(option) {
case 'd':
err_debuglevel = atoi(optarg);
break;
default:
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
usage(-1);
}
}
argc -= optind;
argv += optind;
if(argc == 0) {
fprintf(stderr,"Error: Must specifiy file name\n\n");
usage(-1);
fprintf(stderr,"Error: Must specifiy file name\n\n");
usage(-1);
}
printf("Getting info for %s\n",argv[0]);
@ -170,15 +170,15 @@ int main(int argc, char *argv[]) {
plist=scanner_list;
while(plist->ext && (strcasecmp(plist->ext,ext) != 0)) {
plist++;
plist++;
}
if(plist->ext) {
fprintf(stderr,"dispatching as single-file metatag parser\n");
plist->scanner(argv[0],&mp3);
dump_mp3(&mp3);
fprintf(stderr,"dispatching as single-file metatag parser\n");
plist->scanner(argv[0],&mp3);
dump_mp3(&mp3);
} else {
fprintf(stderr,"unknown file extension: %s\n",ext);
exit(-1);
fprintf(stderr,"unknown file extension: %s\n",ext);
exit(-1);
}
}

View File

@ -10,11 +10,17 @@
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "strptime.h"
#include "err.h"
typedef struct tag_token {
@ -385,7 +391,7 @@ int sp_scan(PARSETREE tree) {
while(*(tree->current) && strchr(" \t\n\r",*(tree->current)))
tree->current++;
tree->token_pos = tree->current - tree->term;
tree->token_pos = (int) (tree->current - tree->term);
if(!*(tree->current)) {
tree->token.token_id = T_EOF;
@ -481,7 +487,7 @@ int sp_scan(PARSETREE tree) {
}
found=0;
len = tail - tree->current;
len = (int) (tail - tree->current);
if(!tree->in_string) {
/* find it in the token list */
@ -1189,16 +1195,16 @@ int sp_node_size(SP_NODE *node) {
size += 7; /* (xxx AND xxx) */
} else {
size = 4; /* parens, plus spaces around op */
size += strlen(node->left.field);
size += (int) strlen(node->left.field);
if((node->op & 0x0FFF) > T_LAST) {
DPRINTF(E_FATAL,L_PARSE,"Can't determine node size: op %04x\n",
node->op);
} else {
size += strlen(sp_token_descr[node->op & 0x0FFF]);
size += (int) strlen(sp_token_descr[node->op & 0x0FFF]);
}
if(node->op_type == SP_OPTYPE_STRING) {
size += (2 + strlen(node->right.cvalue));
size += (2 + (int) strlen(node->right.cvalue));
if(node->op == T_INCLUDES) {
size += 2; /* extra %'s */
}
@ -1319,7 +1325,7 @@ void sp_set_error(PARSETREE tree, int error) {
if(tree->error)
free(tree->error);
len = 10 + (tree->token_pos / 10) + 1 + strlen(sp_errorstrings[error]) + 1;
len = 10 + (tree->token_pos / 10) + 1 + (int) strlen(sp_errorstrings[error]) + 1;
tree->error = (char*)malloc(len);
if(!tree->error) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error");

View File

@ -34,9 +34,12 @@
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <netinet/in.h> /* htons and friends */
#include <sys/stat.h>
#include <dirent.h> /* why here? For osx 10.2, of course! */
#endif
#include <sys/stat.h>
#include "daapd.h"
#include "db-generic.h"

View File

@ -28,9 +28,9 @@
extern int server_side_convert(char *codectype);
extern char *server_side_convert_path(char *path);
extern FILE *server_side_convert_open(char *path,
off_t offset,
unsigned long len_ms,
char *codectype);
off_t offset,
unsigned long len_ms,
char *codectype);
extern void server_side_convert_close(FILE *f);
#endif /* _SCC_H_ */

View File

@ -9,8 +9,8 @@
* matching */
char * strcasestr(char* haystack, char* needle) {
int i;
int nlength = strlen (needle);
int hlength = strlen (haystack);
int nlength = (int) strlen (needle);
int hlength = (int) strlen (haystack);
if (nlength > hlength) return NULL;
if (hlength <= 0) return NULL;

373
src/strptime.c Normal file
View File

@ -0,0 +1,373 @@
/*
* Copyright (c) 1994 Powerdog Industries. All rights reserved.
*
* Redistribution and use in source and binary forms, without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgement:
* This product includes software developed by Powerdog Industries.
* 4. The name of Powerdog Industries may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifndef HAVE_STRPTIME
#include <ctype.h>
#include <time.h>
#include <string.h>
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
#ifndef sun
struct dtconv {
char *abbrev_month_names[12];
char *month_names[12];
char *abbrev_weekday_names[7];
char *weekday_names[7];
char *time_format;
char *sdate_format;
char *dtime_format;
char *am_string;
char *pm_string;
char *ldate_format;
};
#endif
static struct dtconv En_US = {
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
{ "January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December" },
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
{ "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday" },
"%H:%M:%S",
"%m/%d/%y",
"%a %b %e %T %Z %Y",
"AM",
"PM",
"%A, %B, %e, %Y"
};
#ifdef SUNOS4
extern int strncasecmp();
#endif
void lowercase_string(char *buffer) {
while(*buffer) {
*buffer = tolower(*buffer);
buffer++;
}
}
char *strptime(char *buf, char *fmt, struct tm *tm) {
char c,
*ptr;
int i, j,
len;
ptr = fmt;
while (*ptr != 0) {
if (*buf == 0)
break;
c = *ptr++;
if (c != '%') {
if (isspace(c))
while (*buf != 0 && isspace(*buf))
buf++;
else if (c != *buf++)
return 0;
continue;
}
c = *ptr++;
switch (c) {
case 0:
case '%':
if (*buf++ != '%')
return 0;
break;
case 'C':
buf = strptime(buf, En_US.ldate_format, tm);
if (buf == 0)
return 0;
break;
case 'c':
buf = strptime(buf, "%x %X", tm);
if (buf == 0)
return 0;
break;
case 'D':
buf = strptime(buf, "%m/%d/%y", tm);
if (buf == 0)
return 0;
break;
case 'R':
buf = strptime(buf, "%H:%M", tm);
if (buf == 0)
return 0;
break;
case 'r':
buf = strptime(buf, "%I:%M:%S %p", tm);
if (buf == 0)
return 0;
break;
case 'T':
buf = strptime(buf, "%H:%M:%S", tm);
if (buf == 0)
return 0;
break;
case 'X':
buf = strptime(buf, En_US.time_format, tm);
if (buf == 0)
return 0;
break;
case 'x':
buf = strptime(buf, En_US.sdate_format, tm);
if (buf == 0)
return 0;
break;
case 'j':
if (!isdigit(*buf))
return 0;
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
i *= 10;
i += *buf - '0';
}
if (i > 365)
return 0;
tm->tm_yday = i;
break;
case 'M':
case 'S':
if (*buf == 0 || isspace(*buf))
break;
if (!isdigit(*buf))
return 0;
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
i *= 10;
i += *buf - '0';
}
if (i > 59)
return 0;
if (c == 'M')
tm->tm_min = i;
else
tm->tm_sec = i;
if (*buf != 0 && isspace(*buf))
while (*ptr != 0 && !isspace(*ptr))
ptr++;
break;
case 'H':
case 'I':
case 'k':
case 'l':
if (!isdigit(*buf))
return 0;
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
i *= 10;
i += *buf - '0';
}
if (c == 'H' || c == 'k') {
if (i > 23)
return 0;
} else if (i > 11)
return 0;
tm->tm_hour = i;
if (*buf != 0 && isspace(*buf))
while (*ptr != 0 && !isspace(*ptr))
ptr++;
break;
case 'p':
len = (int) strlen(En_US.am_string);
lowercase_string( buf );
if (strncmp(buf, En_US.am_string, len) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour == 12)
tm->tm_hour = 0;
buf += len;
break;
}
len = (int) strlen(En_US.pm_string);
if (strncmp(buf, En_US.pm_string, len) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour != 12)
tm->tm_hour += 12;
buf += len;
break;
}
return 0;
case 'A':
case 'a':
for (i = 0; i < asizeof(En_US.weekday_names); i++) {
len = (int) strlen(En_US.weekday_names[i]);
lowercase_string( buf );
if (strncmp(buf,
En_US.weekday_names[i],
len) == 0)
break;
len = (int) strlen(En_US.abbrev_weekday_names[i]);
if (strncmp(buf,
En_US.abbrev_weekday_names[i],
len) == 0)
break;
}
if (i == asizeof(En_US.weekday_names))
return 0;
tm->tm_wday = i;
buf += len;
break;
case 'd':
case 'e':
if (!isdigit(*buf))
return 0;
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
i *= 10;
i += *buf - '0';
}
if (i > 31)
return 0;
tm->tm_mday = i;
if (*buf != 0 && isspace(*buf))
while (*ptr != 0 && !isspace(*ptr))
ptr++;
break;
case 'B':
case 'b':
case 'h':
for (i = 0; i < asizeof(En_US.month_names); i++) {
len = (int) strlen(En_US.month_names[i]);
lowercase_string( buf );
if (strncmp(buf, En_US.month_names[i],len) == 0)
break;
len = (int) strlen(En_US.abbrev_month_names[i]);
if (strncmp(buf,
En_US.abbrev_month_names[i],
len) == 0)
break;
}
if (i == asizeof(En_US.month_names))
return 0;
tm->tm_mon = i;
buf += len;
break;
case 'm':
if (!isdigit(*buf))
return 0;
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
i *= 10;
i += *buf - '0';
}
if (i < 1 || i > 12)
return 0;
tm->tm_mon = i - 1;
if (*buf != 0 && isspace(*buf))
while (*ptr != 0 && !isspace(*ptr))
ptr++;
break;
case 'Y':
case 'y':
if (*buf == 0 || isspace(*buf))
break;
if (!isdigit(*buf))
return 0;
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<((c=='Y')?4:2); j++,buf++) {
i *= 10;
i += *buf - '0';
}
if (c == 'Y')
i -= 1900;
else if (i < 69) /*c=='y', 00-68 is for 20xx, the rest is for 19xx*/
i += 100;
if (i < 0)
return 0;
tm->tm_year = i;
if (*buf != 0 && isspace(*buf))
while (*ptr != 0 && !isspace(*ptr))
ptr++;
break;
}
}
return buf;
}
#endif /* ndef HAVE_STRPTIME */

39
src/strptime.h Normal file
View File

@ -0,0 +1,39 @@
/******************************************************************************
**
** Copyright (C) 2001 - the shmoo group -
**
** This program is free software; you can redistribute it and/or
** modify it, however, you cannot sell it.
**
** This program 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.
**
** You should have received a copy of the license attached to the
** use of this software. If not, visit www.shmoo.com/osiris for
** details.
**
******************************************************************************/
/******************************************************************************
**
** The Shmoo Group (TSG)
**
** File: strptime.h
** Author: Brian Wotring
**
** Date: June 22, 2001.
** Project: osiris
**
******************************************************************************/
#ifndef STRPTIME_H
#define STRPTIME_H
#ifndef HAVE_STRPTIME
char * strptime( char *buf, char *fmt, struct tm *tm );
#endif
#endif

View File

@ -8,11 +8,11 @@
#if !HAVE_STRSEP
char *strsep(char **stringp, const char *delim) {
char *ret = *stringp;
if (ret == NULL) return(NULL); /* grrr */
if ((*stringp = strpbrk(*stringp, delim)) != NULL) {
*((*stringp)++) = '\0';
}
return(ret);
char *ret = *stringp;
if (ret == NULL) return(NULL); /* grrr */
if ((*stringp = strpbrk(*stringp, delim)) != NULL) {
*((*stringp)++) = '\0';
}
return(ret);
}
#endif /* !HAVE_STRSEP */

88
src/strtok_r.c Normal file
View File

@ -0,0 +1,88 @@
/* Reentrant string tokenizer. Generic version.
Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifndef HAVE_STRTOK_R
#include <stdio.h>
/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the saved pointer in SAVE_PTR is used as
the next starting point. For example:
char s[] = "-abc-=-def";
char *sp;
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
x = strtok_r(NULL, "=", &sp); // x = NULL
// s = "abc\0-def\0"
*/
char *strtok_r(char *s, const char *delim, char **last)
{
char *spanp;
int c, sc;
char *tok;
if (s == NULL && (s = *last) == NULL) {
return NULL;
}
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0; ) {
if (c == sc) {
goto cont;
}
}
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return NULL;
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0) {
s = NULL;
}
else {
char *w = s - 1;
*w = '\0';
}
*last = s;
return tok;
}
}
while (sc != 0);
}
/* NOTREACHED */
}
#endif

49
src/strtok_r.h Normal file
View File

@ -0,0 +1,49 @@
/* Split string into tokens
Copyright (C) 2004-2005 Free Software Foundation, Inc.
Written by Simon Josefsson.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _STRTOK_R_H
#define _STRTOK_R_H
/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the saved pointer in SAVE_PTR is used as
the next starting point. For example:
char s[] = "-abc-=-def";
char *sp;
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
x = strtok_r(NULL, "=", &sp); // x = NULL
// s = "abc\0-def\0"
This is a variant of strtok() that is multithread-safe.
For the POSIX documentation for this function, see:
http://www.opengroup.org/susv3xsh/strtok.html
Caveat: It modifies the original string.
Caveat: These functions cannot be used on constant strings.
Caveat: The identity of the delimiting character is lost.
Caveat: It doesn't work with multibyte strings unless all of the delimiter
characters are ASCII characters < 0x30.
See also strsep().
*/
#ifndef HAVE_STRTOK_R
extern char *strtok_r(char *s, const char *delim, char **last);
#endif
#endif /* _STRTOK_R_H */

View File

@ -175,12 +175,12 @@ int u_connect(u_port_t port, char *hostn) {
if(inet_addr(hostn) == INADDR_NONE) {
phe=gethostbyname(hostn);
if(phe == NULL) {
errno = EINVAL;
return -1;
errno = EINVAL;
return -1;
}
memcpy((char*)&server.sin_addr,(char*)(phe->h_addr_list[0]),
sizeof(struct in_addr));
sizeof(struct in_addr));
} else {
server.sin_addr.s_addr=inet_addr(hostn);
}

127
src/w32-eventlog.c Normal file
View File

@ -0,0 +1,127 @@
/*
* $Id$
*
* eventlog messages utility functions
*
* Copyright (C) 2005-2006 Ron Pedde (ron@pedde.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <windows.h>
#include <stdio.h>
#include "messages.h"
static HANDLE elog_handle = NULL;
/**
* register eventlog functions
*
* @returns TRUE if successful, FALSE otherwise
*/
int elog_register(void) {
HKEY reg_key = NULL;
DWORD err = 0;
char path[MAX_PATH];
DWORD event_types;
wsprintf(path,"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s", PACKAGE);
if((err=RegCreateKey(HKEY_LOCAL_MACHINE, path, &reg_key)) != ERROR_SUCCESS)
return FALSE;
GetModuleFileName(NULL, path, MAX_PATH );
err=RegSetValueEx(reg_key, "EventMessageFile",0,REG_EXPAND_SZ,path,(DWORD)strlen(path) + 1);
if(err != ERROR_SUCCESS) {
RegCloseKey(reg_key);
return FALSE;
}
event_types = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
err=RegSetValueEx(reg_key,"TypesSupported", 0, REG_DWORD, (BYTE*)&event_types, sizeof event_types );
if(err != ERROR_SUCCESS) {
RegCloseKey(reg_key);
return FALSE;
}
RegCloseKey(reg_key);
return TRUE;
}
/**
* FIXME: ENOTIMPL
*/
int elog_unregister(void) {
return TRUE;
}
/**
* initialize the eventlog
*
* @returns TRUE if successful, FALSE otherwise
*/
int elog_init(void) {
elog_handle=RegisterEventSource(NULL, PACKAGE);
if(elog_handle == INVALID_HANDLE_VALUE)
return FALSE;
return TRUE;
}
/**
* uninitialize the eventlog
*
* @returns TRUE
*/
int elog_deinit(void) {
DeregisterEventSource(elog_handle);
return TRUE;
}
/**
* log a message to the event viewer
*
* @param level event level to log: 0=fatal, 3=warn, > info
* @returns TRUE on success, FALSE otherwise
*/
int elog_message(int level, char *msg) {
WORD message_level = EVENTLOG_INFORMATION_TYPE;
int ret;
if(level == 0)
message_level = EVENTLOG_ERROR_TYPE;
ret = ReportEvent(
elog_handle,
message_level,
0,
EVENT_MSG,
NULL,
1,
0,
&msg,
NULL);
/* ReportEvent returns non-zero on success */
return ret ? TRUE : FALSE;
}

32
src/w32-eventlog.h Normal file
View File

@ -0,0 +1,32 @@
/*
* $Id$
*
* eventlog messages utility functions
*
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _EVENTLOG_H_
#define _EVENTLOG_H_
extern int elog_register(void);
extern int elog_unregister(void);
extern int elog_init(void);
extern int elog_deinit(void);
extern int elog_message(int level, char *msg);
#endif /* _EVENTLOG_H_ */

292
src/w32-service.c Normal file
View File

@ -0,0 +1,292 @@
/*
* $Id$
*
* simple service management functions
*
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <windows.h>
#include "daapd.h"
#include "err.h"
/* Forwards */
BOOL service_update_status (DWORD,DWORD,DWORD,DWORD,DWORD);
void service_mainfunc(DWORD, LPTSTR *);
void service_init(void);
void service_handler(DWORD);
/* Globals */
SERVICE_STATUS_HANDLE service_status_handle = NULL;
HANDLE service_kill_event = NULL;
DWORD service_current_status;
/**
* handle the stop, start, pause requests, etc.
*
* @param code action the SCM wants us to take
*/
void service_handler(DWORD code) {
switch(code) {
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
// fallthrough
case SERVICE_CONTROL_STOP:
service_update_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
SetEvent(service_kill_event);
return;
default:
break;
}
service_update_status(service_current_status, NO_ERROR, 0, 0, 0);
}
/**
* exit the service as gracefully as possible, returning the error
* level specified. I think there are some state machine problems
* here, but probably nothing fatal -- an unnecessary call to
* xfer_shutdown, maybe. That's about it.
*
* @param errorlevel errorlevel to return
*/
void service_shutdown(int errorlevel) {
DPRINTF(E_INF,L_MISC,"Service about to terminate with error %d\n",errorlevel);
if(service_current_status != SERVICE_STOPPED) {
service_update_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
config.stop = 1;
service_update_status(SERVICE_STOPPED,errorlevel,0,0,3000);
}
if(service_kill_event) {
SetEvent(service_kill_event);
CloseHandle(service_kill_event);
}
// exit(errorlevel);
/* we'll let the main process exit (or hang!) */
Sleep(5000);
exit(1);
}
/**
* The main for the service -- starts up the service and
* makes it run. This sits in a tight loop until the service
* is shutdown. If this function exits, it's because the
* service is stopping.
*
* @param argc argc as passed from SCM
* @param argv argv as passed from SCM
*/
void service_mainfunc(DWORD argc, LPTSTR *argv) {
BOOL success;
service_current_status = SERVICE_STOPPED;
service_status_handle = RegisterServiceCtrlHandler(PACKAGE,
(LPHANDLER_FUNCTION) service_handler);
if(!service_status_handle) {
service_shutdown(GetLastError());
return;
}
// Next Notify the Service Control Manager of progress
success = service_update_status(SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000);
if (!success) {
service_shutdown(GetLastError());
return;
}
service_kill_event = CreateEvent (0, TRUE, FALSE, 0);
if(!service_kill_event) {
service_shutdown(GetLastError());
return;
}
// FIXME
// startup errors generate an ERR_FATAL, which exit()s in the
// logging code -- fine for console apps, not so good here.
// Generates ugly error messages from the service tool.
// (terminated unexpectedly).
// xfer_startup();
// The service is now running. Notify the SCM of this fact.
service_current_status = SERVICE_RUNNING;
success = service_update_status(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
if (!success) {
service_shutdown(GetLastError());
return;
}
// Now just wait for our killed service signal, and then exit, which
// terminates the service!
WaitForSingleObject (service_kill_event, INFINITE);
service_shutdown(0);
}
/**
* update the scm service status, so it can make pretty
* gui stupidness. light wrapper around SetServiceStatus
*
* If the visual studio editor wasn't so horribly useless
* and munge up the indents, I'd split these parameters
* into several lines, but Microsoft apparently can't build
* an editor that is as good as that made by volunteers.
*
* Those who do not understand Unix are condemned to reinvent
* it, poorly. -- Henry Spencer
*
* @param dwCurrentState new service state
* @param dwWin32ExitCode exit code if state is SERVICE_STOPPED
* @param dwServiceSpecificExitCode specified service exit code
* @param dwCheckPoint incremented value for long startups
* @param dwWaitHint how to before giving up on the service
*
* @returns result of SetServiceStatus - true on success
*/
BOOL service_update_status (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) {
BOOL success;
SERVICE_STATUS serviceStatus;
service_current_status = dwCurrentState;
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = dwCurrentState;
if (dwCurrentState == SERVICE_START_PENDING) {
serviceStatus.dwControlsAccepted = 0;
} else {
serviceStatus.dwControlsAccepted =
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
}
if (dwServiceSpecificExitCode == 0) {
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
} else {
serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
}
serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
serviceStatus.dwCheckPoint = dwCheckPoint;
serviceStatus.dwWaitHint = dwWaitHint;
success = SetServiceStatus (service_status_handle, &serviceStatus);
if (!success) {
SetEvent(service_kill_event);
}
return success;
}
/**
* kick off the application when in service mdoe - suitable for threadprocing
*/
void *service_startup(void *arg) {
SERVICE_TABLE_ENTRY serviceTable[] = {
{ PACKAGE, (LPSERVICE_MAIN_FUNCTION) service_mainfunc },
{ NULL, NULL }
};
BOOL success;
// Register the service with the Service Control Manager
// If it were to fail, what would we do, anyway?
success = StartServiceCtrlDispatcher(serviceTable);
return NULL;
}
/**
* install the service
*/
void service_register(void) {
SC_HANDLE scm;
SC_HANDLE svc;
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH );
if(!(scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE))) {
DPRINTF(E_FATAL,L_MISC,"Cannot open service control manager\n");
}
svc = CreateService(scm,PACKAGE,SERVICENAME,SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,
path,0,0,0,0,0);
if(!svc) {
DPRINTF(E_FATAL,L_MISC,"Cannot create service: %d\n",GetLastError());
}
CloseServiceHandle(svc);
CloseServiceHandle(scm);
DPRINTF(E_LOG,L_MISC,"Registered service successfully\n");
}
/**
* uninstall the service
*/
void service_unregister(void) {
SC_HANDLE scm;
SC_HANDLE svc;
BOOL res;
SERVICE_STATUS status;
if(!(scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE))) {
DPRINTF(E_FATAL,L_MISC,"Cannot open service control manager: %d\n",GetLastError());
}
svc = OpenService(scm,PACKAGE,SERVICE_ALL_ACCESS | DELETE);
if(!svc) {
DPRINTF(E_FATAL,L_MISC,"Cannot open service: %d (is it installed??)\n",GetLastError());
}
res=QueryServiceStatus(svc,&status);
if(!res) {
DPRINTF(E_FATAL,L_MISC,"Cannot query service status: %d\n",GetLastError());
}
if(status.dwCurrentState != SERVICE_STOPPED) {
DPRINTF(E_LOG,L_MISC,"Stopping service...\n");
ControlService(svc,SERVICE_CONTROL_STOP,&status);
// we should probably poll for service stoppage...
Sleep(2000);
}
DPRINTF(E_LOG,L_MISC,"Deleting service...\n");
res = DeleteService(svc);
if(res) {
DPRINTF(E_LOG,L_MISC,"Deleted successfully\n");
} else {
DPRINTF(E_FATAL,L_MISC,"Error deleting service: %d\n",GetLastError());
}
CloseServiceHandle(svc);
CloseServiceHandle(scm);
}

32
src/w32-service.h Normal file
View File

@ -0,0 +1,32 @@
/*
* $Id$
*
* simple service management functions
*
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SERVICE_H_
#define _SERVICE_H_
extern void *service_startup(void *);
extern void service_shutdown(int);
extern void service_register(void);
extern void service_unregister(void);
#endif /* _SERVICE_H_ */

View File

@ -61,43 +61,43 @@ unsigned char *read_hdr(FILE *f, size_t *hdr_len)
hdr = malloc(256);
if (hdr == NULL)
return NULL;
return NULL;
if (fread(hdr, 44, 1, f) != 1)
goto fail;
goto fail;
if (strncmp((char*)hdr + 12, "fmt ", 4))
goto fail;
goto fail;
format_data_length = GET_WAV_INT32(hdr + 16);
if ((format_data_length < 16) || (format_data_length > 100))
goto fail;
goto fail;
*hdr_len = 44;
if (format_data_length > 16) {
if (fread(hdr + 44, format_data_length - 16, 1, f) != 1)
goto fail;
*hdr_len += format_data_length - 16;
if (fread(hdr + 44, format_data_length - 16, 1, f) != 1)
goto fail;
*hdr_len += format_data_length - 16;
}
return hdr;
fail:
if (hdr != NULL)
free(hdr);
free(hdr);
return NULL;
}
size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
unsigned long *chunk_data_length_ret,
unsigned long *format_data_length_ret,
unsigned long *compression_code_ret,
unsigned long *channel_count_ret,
unsigned long *sample_rate_ret,
unsigned long *sample_bit_length_ret,
unsigned long *data_length_ret)
unsigned long *chunk_data_length_ret,
unsigned long *format_data_length_ret,
unsigned long *compression_code_ret,
unsigned long *channel_count_ret,
unsigned long *sample_rate_ret,
unsigned long *sample_bit_length_ret,
unsigned long *data_length_ret)
{
unsigned long chunk_data_length;
unsigned long format_data_length;
@ -108,14 +108,14 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
unsigned long data_length;
if (strncmp((char*)hdr + 0, "RIFF", 4) ||
strncmp((char*)hdr + 8, "WAVE", 4) ||
strncmp((char*)hdr + 12, "fmt ", 4))
return 0;
strncmp((char*)hdr + 8, "WAVE", 4) ||
strncmp((char*)hdr + 12, "fmt ", 4))
return 0;
format_data_length = GET_WAV_INT32(hdr + 16);
if (strncmp((char*)hdr + 20 + format_data_length, "data", 4))
return 0;
return 0;
chunk_data_length = GET_WAV_INT32(hdr + 4);
compression_code = GET_WAV_INT16(hdr + 20);
@ -125,12 +125,12 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
data_length = GET_WAV_INT32(hdr + 20 + format_data_length + 4);
if ((format_data_length != 16) ||
(compression_code != 1) ||
(channel_count < 1) ||
(sample_rate == 0) ||
(sample_rate > 512000) ||
(sample_bit_length < 2))
return 0;
(compression_code != 1) ||
(channel_count < 1) ||
(sample_rate == 0) ||
(sample_rate > 512000) ||
(sample_bit_length < 2))
return 0;
*chunk_data_length_ret = chunk_data_length;
*format_data_length_ret = format_data_length;
@ -144,9 +144,9 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
}
size_t patch_hdr(unsigned char *hdr, size_t hdr_len,
unsigned long sec, unsigned long us,
unsigned long samples,
size_t *data_length_ret)
unsigned long sec, unsigned long us,
unsigned long samples,
size_t *data_length_ret)
{
unsigned long chunk_data_length;
unsigned long format_data_length;
@ -158,45 +158,45 @@ size_t patch_hdr(unsigned char *hdr, size_t hdr_len,
unsigned long bytes_per_sample;
if (parse_hdr(hdr, hdr_len,
&chunk_data_length,
&format_data_length,
&compression_code,
&channel_count,
&sample_rate,
&sample_bit_length,
&data_length) != hdr_len)
return 0;
&chunk_data_length,
&format_data_length,
&compression_code,
&channel_count,
&sample_rate,
&sample_bit_length,
&data_length) != hdr_len)
return 0;
if (hdr_len != (20 + format_data_length + 8))
return 0;
return 0;
if (format_data_length > 16) {
memmove(hdr + 20 + 16, hdr + 20 + format_data_length, 8);
hdr[16] = 16;
hdr[17] = 0;
hdr[18] = 0;
hdr[19] = 0;
format_data_length = 16;
hdr_len = 44;
memmove(hdr + 20 + 16, hdr + 20 + format_data_length, 8);
hdr[16] = 16;
hdr[17] = 0;
hdr[18] = 0;
hdr[19] = 0;
format_data_length = 16;
hdr_len = 44;
}
bytes_per_sample = channel_count * ((sample_bit_length + 7) / 8);
if (samples == 0) {
samples = sample_rate * sec;
samples += ((sample_rate / 100) * (us / 10)) / 1000;
samples = sample_rate * sec;
samples += ((sample_rate / 100) * (us / 10)) / 1000;
}
if (samples > 0) {
data_length = samples * bytes_per_sample;
chunk_data_length = data_length + 36;
data_length = samples * bytes_per_sample;
chunk_data_length = data_length + 36;
} else {
chunk_data_length = 0xffffffff;
data_length = chunk_data_length - 36;
chunk_data_length = 0xffffffff;
data_length = chunk_data_length - 36;
}
if (data_length_ret != NULL)
*data_length_ret = data_length;
*data_length_ret = data_length;
hdr[4] = chunk_data_length % 0x100;
hdr[5] = (chunk_data_length >> 8) % 0x100;
@ -216,25 +216,25 @@ static void usage(int exitval);
static void usage(int exitval)
{
fprintf(stderr,
"Usage: %s [ options ] [input-file]\n", av0);
"Usage: %s [ options ] [input-file]\n", av0);
fprintf(stderr,
"\n");
"\n");
fprintf(stderr,
"Options:\n");
"Options:\n");
fprintf(stderr,
"-l len | --length=len Length of the sound file in seconds.\n");
"-l len | --length=len Length of the sound file in seconds.\n");
fprintf(stderr,
"-s len | --samples=len Length of the sound file in samples.\n");
"-s len | --samples=len Length of the sound file in samples.\n");
fprintf(stderr,
"-o offset | --offset=offset Number of bytes to discard from the stream.\n");
"-o offset | --offset=offset Number of bytes to discard from the stream.\n");
fprintf(stderr,
"\n");
"\n");
fprintf(stderr,
"--samples and --length are mutually exclusive.\n");
"--samples and --length are mutually exclusive.\n");
#if 1
fprintf(stderr,
"\n\nLong options are not available on this system.\n");
"\n\nLong options are not available on this system.\n");
#endif
exit(exitval);
@ -254,127 +254,127 @@ int main(int argc, char **argv)
size_t buf_len;
if (strchr(argv[0], '/'))
av0 = strrchr(argv[0], '/') + 1;
av0 = strrchr(argv[0], '/') + 1;
else
av0 = argv[0];
av0 = argv[0];
#if 0
while ((c = getopt_long(argc, argv, "+hl:o:s:", longopts, NULL)) != EOF) {
#else
while ((c = getopt(argc, argv, "hl:o:s:")) != -1) {
#endif
switch(c) {
case 'h':
usage(0);
/*NOTREACHED*/
break;
case 'l':
sec = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || ((*end != '\0') && (*end != '.'))) {
fprintf(stderr, "%s: Invalid -l argument.\n", av0);
exit(-1);
} else if (*end == '.') {
char tmp[7];
int i;
memset(tmp, '0', sizeof (tmp) - 1);
tmp[sizeof (tmp) - 1] = '\0';
for (i = 0; (i < (sizeof (tmp) - 1)) && (isdigit(end[i+1])); i++)
tmp[i] = end[i+1];
us = strtoul(tmp, NULL, 10);
} else {
us = 0;
}
switch(c) {
case 'h':
usage(0);
/*NOTREACHED*/
break;
case 'l':
sec = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || ((*end != '\0') && (*end != '.'))) {
fprintf(stderr, "%s: Invalid -l argument.\n", av0);
exit(-1);
} else if (*end == '.') {
char tmp[7];
int i;
memset(tmp, '0', sizeof (tmp) - 1);
tmp[sizeof (tmp) - 1] = '\0';
for (i = 0; (i < (sizeof (tmp) - 1)) && (isdigit(end[i+1])); i++)
tmp[i] = end[i+1];
us = strtoul(tmp, NULL, 10);
} else {
us = 0;
}
/*
if ((sec == 0) && (us == 0)) {
fprintf(stderr, "%s: Invalid -l argument (zero is not acceptable).\n", av0);
exit(-1);
}
*/
/*
if ((sec == 0) && (us == 0)) {
fprintf(stderr, "%s: Invalid -l argument (zero is not acceptable).\n", av0);
exit(-1);
}
*/
if (samples != 0) {
fprintf(stderr, "%s: Parameters -s and -l are mutually exclusive.\n", av0);
exit(-1);
}
break;
case 's':
samples = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
fprintf(stderr, "%s: Invalid -s argument.\n", av0);
exit(-1);
}
if (samples == 0) {
fprintf(stderr, "%s: Invalid -s argument (zero is not acceptable).\n", av0);
exit(-1);
}
if ((sec != 0) || (us != 0)) {
fprintf(stderr, "%s: Parameters -l and -s are mutually exclusive.\n", av0);
exit(-1);
}
break;
case 'o':
offset = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
fprintf(stderr, "%s: Invalid -o argument.\n", av0);
exit(-1);
}
break;
default:
fprintf(stderr, "%s: Bad command line option -%c.\n", av0, optopt);
usage(-1);
}
if (samples != 0) {
fprintf(stderr, "%s: Parameters -s and -l are mutually exclusive.\n", av0);
exit(-1);
}
break;
case 's':
samples = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
fprintf(stderr, "%s: Invalid -s argument.\n", av0);
exit(-1);
}
if (samples == 0) {
fprintf(stderr, "%s: Invalid -s argument (zero is not acceptable).\n", av0);
exit(-1);
}
if ((sec != 0) || (us != 0)) {
fprintf(stderr, "%s: Parameters -l and -s are mutually exclusive.\n", av0);
exit(-1);
}
break;
case 'o':
offset = strtoul(optarg, &end, 10);
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
fprintf(stderr, "%s: Invalid -o argument.\n", av0);
exit(-1);
}
break;
default:
fprintf(stderr, "%s: Bad command line option -%c.\n", av0, optopt);
usage(-1);
}
}
argc -= optind;
argv += optind;
if (argc == 0) {
f = stdin;
f = stdin;
} else if (argc == 1) {
f = fopen(argv[0], "rb");
if (f == NULL) {
fprintf(stderr, "%s: Can't open file %s for reading.\n", av0, argv[0]);
exit(1);
}
f = fopen(argv[0], "rb");
if (f == NULL) {
fprintf(stderr, "%s: Can't open file %s for reading.\n", av0, argv[0]);
exit(1);
}
} else {
fprintf(stderr, "%s: Too many command line arguments.\n", av0);
usage(-1);
fprintf(stderr, "%s: Too many command line arguments.\n", av0);
usage(-1);
}
hdr = read_hdr(f, &hdr_len);
if (hdr == NULL) {
fprintf(stderr, "%s: Can't read wav header.\n", av0);
exit(2);
fprintf(stderr, "%s: Can't read wav header.\n", av0);
exit(2);
}
if ((hdr_len = patch_hdr(hdr, hdr_len, sec, us, samples, &data_len)) == 0) {
free(hdr);
fprintf(stderr, "%s: Can't parse (or patch) wav header.\n", av0);
exit(2);
free(hdr);
fprintf(stderr, "%s: Can't parse (or patch) wav header.\n", av0);
exit(2);
}
if (offset > hdr_len + data_len) {
fprintf(stderr, "%s: Offset is beyond EOF.\n", av0);
exit(3);
fprintf(stderr, "%s: Offset is beyond EOF.\n", av0);
exit(3);
}
if ((offset > 0) && (offset < hdr_len)) {
memmove(hdr, hdr + offset, hdr_len - offset);
hdr_len -= offset;
offset = 0;
memmove(hdr, hdr + offset, hdr_len - offset);
hdr_len -= offset;
offset = 0;
}
if (offset > 0) {
offset -= hdr_len;
offset -= hdr_len;
} else {
if (fwrite(hdr, hdr_len, 1, stdout) != 1) {
fprintf(stderr, "%s: Write failed.\n", av0);
exit(4);
}
if (fwrite(hdr, hdr_len, 1, stdout) != 1) {
fprintf(stderr, "%s: Write failed.\n", av0);
exit(4);
}
}
free(hdr);
@ -382,32 +382,32 @@ int main(int argc, char **argv)
hdr_len = 0;
if (offset > 0) {
data_len -= offset;
while (offset > 0) {
buf_len = (offset > sizeof (buf)) ? sizeof (buf) : offset;
if (fread(buf, buf_len, 1, f) != 1) {
fprintf(stderr, "%s: Read failed.\n", av0);
exit(5);
}
offset -= buf_len;
}
data_len -= offset;
while (offset > 0) {
buf_len = (offset > sizeof (buf)) ? sizeof (buf) : offset;
if (fread(buf, buf_len, 1, f) != 1) {
fprintf(stderr, "%s: Read failed.\n", av0);
exit(5);
}
offset -= buf_len;
}
}
while (data_len > 0) {
buf_len = (data_len > sizeof (buf)) ? sizeof (buf) : data_len;
if (fread(buf, buf_len, 1, f) != 1) {
fprintf(stderr, "%s: Read failed.\n", av0);
exit(5);
}
if (fwrite(buf, buf_len, 1, stdout) != 1) {
fprintf(stderr, "%s: Write failed.\n", av0);
exit(4);
}
data_len -= buf_len;
buf_len = (data_len > sizeof (buf)) ? sizeof (buf) : data_len;
if (fread(buf, buf_len, 1, f) != 1) {
fprintf(stderr, "%s: Read failed.\n", av0);
exit(5);
}
if (fwrite(buf, buf_len, 1, stdout) != 1) {
fprintf(stderr, "%s: Write failed.\n", av0);
exit(4);
}
data_len -= buf_len;
}
if (f != stdout) {
fclose(f);
fclose(f);
}
exit(0);
}

View File

@ -20,7 +20,7 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "config.h"
#endif
#include <ctype.h>
@ -29,21 +29,27 @@
#include <limits.h>
#include <pthread.h>
#include <regex.h>
#include <restart.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <uici.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifndef WIN32
# include <sys/param.h>
# include <sys/types.h>
# include <sys/socket.h>
#endif
#include "err.h"
#include "restart.h"
#include "webserver.h"
#ifndef WIN32 /* FIXME: the uici stuff should be moved into os-win32 and os-unix
* as os_opensocket, os_accept, etc */
# include "uici.h"
#endif
/*
* Defines
*/
@ -343,7 +349,7 @@ extern int ws_stop(WSHANDLE ws) {
DPRINTF(E_DBG,L_WS,"ws_stop: closing the server fd\n");
shutdown(pwsp->server_fd,SHUT_RDWR);
r_close(pwsp->server_fd); /* this should tick off the listener */
r_close(pwsp->server_fd);
/* wait for the server thread to terminate. SHould be quick! */
pthread_join(pwsp->server_tid,&result);
@ -434,7 +440,7 @@ void *ws_mainthread(void *arg) {
ws_lock_unsafe();
pwsc->threadno=pwsp->threadno;
pwsp->threadno++;
/* we'll hold the unsafe until the dispatch thread is registered */
/* we'll hold the unsafe until the dispatch thread is registered */
/* now, throw off a dispatch thread */
if((err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc))) {
@ -445,7 +451,7 @@ void *ws_mainthread(void *arg) {
ws_add_dispatch_thread(pwsp,pwsc);
pthread_detach(tid);
}
ws_unlock_unsafe();
ws_unlock_unsafe();
}
DPRINTF(E_SPAM,L_WS,"Exiting ws_mainthred\n");
@ -488,17 +494,17 @@ void ws_close(WS_CONNINFO *pwsc) {
ws_remove_dispatch_thread(pwsp, pwsc);
/* Get rid of the local storage */
if(pwsc->local_storage) {
if(pwsc->storage_callback) {
pwsc->storage_callback(pwsc->local_storage);
pwsc->local_storage=NULL;
pwsc->storage_callback=NULL;
}
}
/* Get rid of the local storage */
if(pwsc->local_storage) {
if(pwsc->storage_callback) {
pwsc->storage_callback(pwsc->local_storage);
pwsc->local_storage=NULL;
pwsc->storage_callback=NULL;
}
}
free(pwsc->hostname);
memset(pwsc,0x00,sizeof(WS_CONNINFO));
memset(pwsc,0x00,sizeof(WS_CONNINFO));
free(pwsc);
DPRINTF(E_SPAM,L_WS,"Exiting ws_close (thread terminating)\n");
pthread_exit(NULL);
@ -1033,14 +1039,14 @@ int ws_returnerror(WS_CONNINFO *pwsc,int error, char *description) {
* and serves it up
*/
void ws_defaulthandler(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
char path[MAXPATHLEN];
char resolved_path[MAXPATHLEN];
char path[PATH_MAX];
char resolved_path[PATH_MAX];
int file_fd;
off_t len;
DPRINTF(E_SPAM,L_WS,"Entering ws_defaulthandler\n");
snprintf(path,MAXPATHLEN,"%s/%s",pwsp->wsconfig.web_root,pwsc->uri);
snprintf(path,PATH_MAX,"%s/%s",pwsp->wsconfig.web_root,pwsc->uri);
if(!realpath(path,resolved_path)) {
pwsc->error=errno;
DPRINTF(E_WARN,L_WS,"Exiting ws_defaulthandler: Cannot resolve %s\n",path);
@ -1577,7 +1583,7 @@ WS_CONNINFO *ws_thread_enum_first(WSHANDLE wsh, WSTHREADENUM *vpp) {
if(pconlist) {
pwsc = pconlist->pwsc;
} else {
ws_unlock_connlist(pwsp);
ws_unlock_connlist(pwsp);
}
return pwsc;

View File

@ -75,9 +75,9 @@ typedef struct tag_ws_conninfo {
extern WSHANDLE ws_start(WSCONFIG *config);
extern int ws_stop(WSHANDLE ws);
extern int ws_registerhandler(WSHANDLE ws, char *regex,
void(*handler)(WS_CONNINFO*),
int(*auth)(char *, char *),
int addheaders);
void(*handler)(WS_CONNINFO*),
int(*auth)(char *, char *),
int addheaders);
extern void ws_lock_local_storage(WS_CONNINFO *pwsc);
extern void ws_unlock_local_storage(WS_CONNINFO *pwsc);

79
src/win32.h Normal file
View File

@ -0,0 +1,79 @@
/*
* $Id$
*
* Win32 compatibility stuff
*/
#ifndef _WIN32_H_
#define _WIN32_H_
#include <windows.h>
//#include <winsock2.h>
#include <io.h>
#include <stddef.h>
#include <fcntl.h>
#include <direct.h>
#include "os-win32.h"
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
/* Funtion fixups */
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define usleep Sleep
#define sleep(a) Sleep((a) * 1000)
#define read(a,b,c) os_read((a),(b),(int)(c))
#define write(a,b,c) os_write((a),(b),(int)(c))
#define strncasecmp strnicmp
#define strcasecmp stricmp
#define mkdir(a,b) _mkdir((a))
#define popen _popen
#define pclose _pclose
#define strtoll strtol
#define realpath os_realpath
#define close os_close
#define strsep os_strsep
#define open os_open
#define waitfdtimed os_waitfdtimed
#define readdir_r os_readdir_r
#define closedir os_closedir
#define opendir os_opendir
#define getuid os_getuid
#define strerror os_strerror
/* override the uici stuff */
#define u_open os_opensocket
#define u_accept os_acceptsocket
/* privately implemented functions: @see os-win32.c */
#define gettimeofday os_gettimeofday
/* Type fixups */
#define mode_t int
#define ssize_t int
#define socklen_t int
/* Consts */
#define PIPE_BUF 256 /* What *should* this be on win32? */
#define MAXDESC 512 /* http://msdn.microsoft.com/en-us/library/kdfaxaay.aspx */
#define SHUT_RDWR 2
#define MAX_NAME_LEN _MAX_PATH
#define ETIME 101
#define PATH_MAX _MAX_PATH
#define HOST "unknown-windows-ick"
#define SERVICENAME "Multithreaded DAAP Server"
#define DEFAULT_CONFIGFILE os_configpath()
extern char *os_configpath(void);
#endif /* _WIN32_H_ */

View File

@ -4,6 +4,10 @@
* This really isn't xmlrpc. It's xmlrpc-ish. Emphasis on -ish.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
@ -242,7 +246,7 @@ void xml_get_stats(WS_CONNINFO *pwsc) {
xml_push(pxml,"statistics");
r_secs=time(NULL)-config.stats.start_time;
r_secs=(int)(time(NULL)-config.stats.start_time);
r_days=r_secs/(3600 * 24);
r_secs -= ((3600 * 24) * r_days);
@ -300,7 +304,7 @@ char *xml_entity_encode(char *original) {
char *s, *d;
int destsize;
destsize = 6*strlen(original)+1;
destsize = 6*(int)strlen(original)+1;
new=(char *)malloc(destsize);
if(!new) return NULL;