[Redbutton-devel] SF.net SVN: redbutton: [10] redbutton-browser/trunk
Brought to you by:
skilvington
|
From: <ski...@us...> - 2006-03-02 17:10:33
|
Revision: 10 Author: skilvington Date: 2006-03-02 09:10:15 -0800 (Thu, 02 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=10&view=rev Log Message: ----------- allow rb-browser to use remote backends Modified Paths: -------------- redbutton-browser/trunk/MHEGApp.c redbutton-browser/trunk/MHEGApp.h redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGDisplay.c redbutton-browser/trunk/MHEGDisplay.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-browser/trunk/TODO redbutton-browser/trunk/rb-browser.c redbutton-browser/trunk/utils.c redbutton-browser/trunk/utils.h redbutton-download/trunk/listen.c Modified: redbutton-browser/trunk/MHEGApp.c =================================================================== --- redbutton-browser/trunk/MHEGApp.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGApp.c 2006-03-02 17:10:15 UTC (rev 10) @@ -21,7 +21,7 @@ } void -MHEGApp_stop(MHEGApp *m) +MHEGApp_fini(MHEGApp *m) { if(m->app != NULL) free_InterchangedObject(m->app); @@ -63,7 +63,7 @@ if((der = MHEGEngine_openFile(derfile, "r")) == NULL) { - error("Unable to open '%.*s': %s", derfile->size, derfile->data, strerror(errno)); + error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->app); m->app = NULL; return NULL; @@ -118,7 +118,7 @@ if((der = MHEGEngine_openFile(derfile, "r")) == NULL) { - error("Unable to open '%.*s': %s", derfile->size, derfile->data, strerror(errno)); + error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->scene); m->scene = NULL; return NULL; Modified: redbutton-browser/trunk/MHEGApp.h =================================================================== --- redbutton-browser/trunk/MHEGApp.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGApp.h 2006-03-02 17:10:15 UTC (rev 10) @@ -14,7 +14,7 @@ } MHEGApp; void MHEGApp_init(MHEGApp *); -void MHEGApp_stop(MHEGApp *); +void MHEGApp_fini(MHEGApp *); ApplicationClass *MHEGApp_loadApplication(MHEGApp *, OctetString *); SceneClass *MHEGApp_loadScene(MHEGApp *, OctetString *); Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-02 17:10:15 UTC (rev 10) @@ -2,62 +2,211 @@ * MHEGBackend.c */ +#include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/socket.h> #include "MHEGEngine.h" #include "utils.h" +/* local backend funcs */ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *local_openFile(MHEGBackend *, OctetString *, char *); int local_closeFile(MHEGBackend *, FILE *); -static MHEGBackend local_backend = +static struct MHEGBackendFns local_backend_fns = { - NULL, /* base_dir */ local_checkContentRef, /* checkContentRef */ local_loadFile, /* loadFile */ local_openFile, /* openFile */ local_closeFile /* closeFile */ }; -MHEGBackend * -new_MHEGBackend(bool remote, char *srg_loc) +/* remote backend funcs */ +bool remote_checkContentRef(MHEGBackend *, ContentReference *); +bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); +FILE *remote_openFile(MHEGBackend *, OctetString *, char *); +int remote_closeFile(MHEGBackend *, FILE *); + +static struct MHEGBackendFns remote_backend_fns = { - MHEGBackend *b = NULL; + remote_checkContentRef, /* checkContentRef */ + remote_loadFile, /* loadFile */ + remote_openFile, /* openFile */ + remote_closeFile /* closeFile */ +}; +/* internal functions */ +static int parse_addr(char *, struct in_addr *, in_port_t *); +static int get_host_addr(char *, struct in_addr *); + +static int remote_command(MHEGBackend *, char *); +static unsigned int remote_response(int); + +/* public interface */ +void +MHEGBackend_init(MHEGBackend *b, bool remote, char *srg_loc) +{ + bzero(b, sizeof(MHEGBackend)); + if(remote) { - /* backend is on a different host, srg_loc is the remote host */ -/* TODO */ -fatal("TODO: remote backends not supported: %s", srg_loc); + /* backend is on a different host, srg_loc is the remote host[:port] */ + b->fns = &remote_backend_fns; + b->addr.sin_family = AF_INET; + b->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + b->addr.sin_port = htons(DEFAULT_REMOTE_PORT); + if(parse_addr(srg_loc, &b->addr.sin_addr, &b->addr.sin_port) < 0) + fatal("Unable to resolve host %s", srg_loc); + verbose("Remote backend at %s:%u", inet_ntoa(b->addr.sin_addr), ntohs(b->addr.sin_port)); } else { /* backend and frontend on same host, srg_loc is the base directory */ - b = &local_backend; + b->fns = &local_backend_fns; b->base_dir = srg_loc; + verbose("Local backend; carousel file root '%s'", srg_loc); } - return b; + return; } void -free_MHEGBackend(MHEGBackend *b) +MHEGBackend_fini(MHEGBackend *b) { return; } /* + * extract the IP addr and port number from a string in one of these forms: + * host:port + * ip-addr:port + * host + * ip-addr + * if the port is not defined in the string, the value passed to this routine is unchanged + * ip and port are both returned in network byte order + * returns -1 on error (can't resolve host name) + */ + +static int +parse_addr(char *str, struct in_addr *ip, in_port_t *port) +{ + char *p; + + if((p = strchr(str, ':')) != NULL) + { + /* its either host:port or ip:port */ + *(p++) = '\0'; + if(get_host_addr(str, ip) < 0) + return -1; + *port = htons(atoi(p)); + /* reconstruct the string */ + *(--p) = ':'; + } + else if(get_host_addr(str, ip) < 0) + { + return -1; + } + + return 0; +} + +/* + * puts the IP address associated with the given host into output buffer + * host can be a.b.c.d or a host name + * returns 0 if successful, -1 on error + */ + +static int +get_host_addr(char *host, struct in_addr *output) +{ + struct hostent *he; + int error = 0; + + if(((he = gethostbyname(host)) != NULL) && (he->h_addrtype == AF_INET)) + memcpy(output, he->h_addr, sizeof(struct in_addr)); + else + error = -1; + + return error; +} + +/* + * send the given command to the remote backend + * returns a socket fd to read the response from + * returns <0 if it can't contact the backend + */ + +static int +remote_command(MHEGBackend *t, char *cmd) +{ + int sock; + + /* connect to the backend */ + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error("Unable to create backend socket: %s", strerror(errno)); + return -1; + } + + if(connect(sock, (struct sockaddr *) &t->addr, sizeof(struct sockaddr_in)) < 0) + { + error("Unable to connect to backend: %s", strerror(errno)); + return -1; + } + + /* send the command */ + write_string(sock, cmd); + + return sock; +} + +/* + * read the backend response from the given socket fd + * returns the OK/error code + */ + +#define BACKEND_RESPONSE_OK 200 + +static unsigned int +remote_response(int sock) +{ + char buf[1024]; + char byte; + unsigned int total; + ssize_t nread; + unsigned int rc; + + /* read upto \n */ + total = 0; + do + { + if((nread = read(sock, &byte, 1)) == 1) + buf[total++] = byte; + } + while(nread == 1 && byte != '\n' && total < (sizeof(buf) - 1)); + + /* \0 terminate it */ + buf[total] = '\0'; + + rc = atoi(buf); + + return rc; +} + +/* * local routines */ /* * returns a filename that can be loaded from the file system * ie ~// at the start of the absolute name is replaced with base_dir - * returns a ptr to static string that will be overwritten by the next call to this routine + * returns a ptr to a static string that will be overwritten by the next call to this routine */ static char _external[PATH_MAX]; @@ -71,7 +220,7 @@ absolute = MHEGEngine_absoluteFilename(name); /* construct the filename */ - snprintf(_external, sizeof(_external), "%s%s", t->base_dir, &absolute[1]); + snprintf(_external, sizeof(_external), "%s%s", t->base_dir, &absolute[2]); return _external; } @@ -98,6 +247,7 @@ /* * file contents are stored in out (out->data will need to be free'd) * returns false if it can't load the file (out will be {0,NULL}) + * out should be {0,NULL} before calling this */ bool @@ -106,16 +256,6 @@ char *fullname; FILE *file; - out->size = 0; - out->data = NULL; - - /* just in case */ - if(name->size == 0) - { - verbose("local_loadFile: no filename given"); - return false; - } - fullname = external_filename(t, name); /* open it */ @@ -162,3 +302,136 @@ return fclose(file); } +/* + * remote routines + */ + +/* + * returns true if the file exists on the carousel + */ + +bool +remote_checkContentRef(MHEGBackend *t, ContentReference *name) +{ + char cmd[PATH_MAX]; + int sock; + bool exists; + + snprintf(cmd, sizeof(cmd), "check %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return false; + + exists = (remote_response(sock) == BACKEND_RESPONSE_OK); + + close(sock); + + return exists; +} + +/* + * file contents are stored in out (out->data will need to be free'd) + * returns false if it can't load the file (out will be {0,NULL}) + * out should be {0,NULL} before calling this + */ + +bool +remote_loadFile(MHEGBackend *t, OctetString *name, OctetString *out) +{ + char cmd[PATH_MAX]; + int sock; + char buf[8 * 1024]; + ssize_t nread; + bool success = false; + + snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return false; + + /* does it exist */ + if(remote_response(sock) == BACKEND_RESPONSE_OK) + { + verbose("Loading '%.*s'", name->size, name->data); + /* read from the socket until EOF */ + do + { + if((nread = read(sock, buf, sizeof(buf))) > 0) + { + out->data = safe_realloc(out->data, out->size + nread); + memcpy(out->data + out->size, buf, nread); + out->size += nread; + } + } + while(nread > 0); + success = true; + } + else + { + error("Unable to load '%.*s'", name->size, name->data); + } + + close(sock); + + return success; +} + +FILE * +remote_openFile(MHEGBackend *t, OctetString *name, char *mode) +{ + char cmd[PATH_MAX]; + int sock; + char buf[8 * 1024]; + ssize_t nread; + size_t nwritten; + FILE *file = NULL; + + snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return NULL; + + /* does it exist */ + if(remote_response(sock) == BACKEND_RESPONSE_OK) + { + if((file = tmpfile()) != NULL) + { + /* read from the socket until EOF */ + do + { + if((nread = read(sock, buf, sizeof(buf))) > 0) + nwritten = fwrite(buf, 1, nread, file); + else + nwritten = 0; + } + while(nread > 0 && nread == nwritten); + /* could we write the file ok */ + if(nread != nwritten) + { + error("Unable to write to local file"); + fclose(file); + file = NULL; + } + } + } + + close(sock); + + /* rewind the file */ + if(file != NULL) + rewind(file); + + return file; +} + +/* + * close a FILE opened with MHEGEngine_openFile() + */ + +int +remote_closeFile(MHEGBackend *t, FILE *file) +{ + /* tmpfile() will delete the file for us */ + return fclose(file); +} + Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-02 17:10:15 UTC (rev 10) @@ -7,17 +7,26 @@ #include <stdio.h> #include <stdbool.h> +#include <netinet/in.h> +/* default TCP port to contact backend on */ +#define DEFAULT_REMOTE_PORT 10101 + typedef struct MHEGBackend { - char *base_dir; /* Service Gateway root directory */ - bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ - bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ - FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ - int (*closeFile)(struct MHEGBackend *, FILE *); /* close a file */ + char *base_dir; /* local Service Gateway root directory */ + struct sockaddr_in addr; /* remote backend IP and port */ + /* function pointers */ + struct MHEGBackendFns + { + bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ + bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ + FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ + int (*closeFile)(struct MHEGBackend *, FILE *); /* close a file */ + } *fns; } MHEGBackend; -MHEGBackend *new_MHEGBackend(bool, char *); -void free_MHEGBackend(MHEGBackend *); +void MHEGBackend_init(MHEGBackend *, bool, char *); +void MHEGBackend_fini(MHEGBackend *); #endif /* __MHEGBACKEND_H__ */ Modified: redbutton-browser/trunk/MHEGDisplay.c =================================================================== --- redbutton-browser/trunk/MHEGDisplay.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGDisplay.c 2006-03-02 17:10:15 UTC (rev 10) @@ -240,7 +240,7 @@ } void -MHEGDisplay_stop(MHEGDisplay *d) +MHEGDisplay_fini(MHEGDisplay *d) { /* calls XCloseDisplay for us which free's all our Windows, Pixmaps, etc */ XtDestroyApplicationContext(d->app); Modified: redbutton-browser/trunk/MHEGDisplay.h =================================================================== --- redbutton-browser/trunk/MHEGDisplay.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGDisplay.h 2006-03-02 17:10:15 UTC (rev 10) @@ -52,7 +52,7 @@ } MHEGDisplay; void MHEGDisplay_init(MHEGDisplay *, bool, char *); -void MHEGDisplay_stop(MHEGDisplay *); +void MHEGDisplay_fini(MHEGDisplay *); bool MHEGDisplay_processEvents(MHEGDisplay *, bool); Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGEngine.c 2006-03-02 17:10:15 UTC (rev 10) @@ -173,7 +173,7 @@ MHEGDisplay_init(&engine.display, fullscreen, keymap); - engine.backend = new_MHEGBackend(remote, srg_loc); + MHEGBackend_init(&engine.backend, remote, srg_loc); MHEGApp_init(&engine.active_app); @@ -223,7 +223,7 @@ ApplicationClass_Deactivation(app); ApplicationClass_Destruction(app); /* clean up */ - MHEGApp_stop(&engine.active_app); + MHEGApp_fini(&engine.active_app); LIST_FREE(&engine.objects, RootClassPtr, safe_free); LIST_FREE(&engine.missing_content, MissingContent, free_MissingContentListItem); LIST_FREE(&engine.active_links, LinkClassPtr, safe_free); @@ -264,15 +264,15 @@ } void -MHEGEngine_stop(void) +MHEGEngine_fini(void) { - MHEGDisplay_stop(&engine.display); + MHEGDisplay_fini(&engine.display); LIST_FREE(&engine.persistent, PersistentData, free_PersistentDataListItem); si_free(); - free_MHEGBackend(engine.backend); + MHEGBackend_fini(&engine.backend); return; } @@ -1293,18 +1293,30 @@ bool MHEGEngine_checkContentRef(ContentReference *name) { - return (*(engine.backend->checkContentRef))(engine.backend, name); + return (*(engine.backend.fns->checkContentRef))(&engine.backend, name); } /* * file contents are stored in out (out->data will need to be free'd) * returns false if it can't load the file (out will be {0,NULL}) + * out should be uninitialised before calling this */ bool MHEGEngine_loadFile(OctetString *name, OctetString *out) { - return (*(engine.backend->loadFile))(engine.backend, name, out); + /* in case it fails */ + out->size = 0; + out->data = NULL; + + /* just in case */ + if(name->size == 0) + { + verbose("MHEGEngine_loadFile: no filename given"); + return false; + } + + return (*(engine.backend.fns->loadFile))(&engine.backend, name, out); } /* @@ -1316,7 +1328,7 @@ FILE * MHEGEngine_openFile(OctetString *name, char *mode) { - return (*(engine.backend->openFile))(engine.backend, name, mode); + return (*(engine.backend.fns->openFile))(&engine.backend, name, mode); } /* @@ -1326,7 +1338,7 @@ int MHEGEngine_closeFile(FILE *file) { - return (*(engine.backend->closeFile))(engine.backend, file); + return (*(engine.backend.fns->closeFile))(&engine.backend, file); } /* Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGEngine.h 2006-03-02 17:10:15 UTC (rev 10) @@ -154,7 +154,7 @@ int verbose; /* -v cmd line flag */ unsigned int timeout; /* how long to poll for missing content before generating an error */ MHEGDisplay display; /* make porting easier */ - MHEGBackend *backend; /* local or remote access to DSMCC carousel and MPEG streams */ + MHEGBackend backend; /* local or remote access to DSMCC carousel and MPEG streams */ MHEGApp active_app; /* application we are currently running */ QuitReason quit_reason; /* do we need to stop the current app */ OctetString quit_data; /* new app to Launch or Spawn, or channel to Retune to */ @@ -171,7 +171,7 @@ /* prototypes */ void MHEGEngine_init(bool, char *, int, unsigned int, bool, char *); int MHEGEngine_run(OctetString *); -void MHEGEngine_stop(); +void MHEGEngine_fini(); MHEGDisplay *MHEGEngine_getDisplay(void); Modified: redbutton-browser/trunk/TODO =================================================================== --- redbutton-browser/trunk/TODO 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/TODO 2006-03-02 17:10:15 UTC (rev 10) @@ -1,3 +1,6 @@ +handle SIGPIPE - default handler terminates the process + + are all inherited instance vars added to classes? @@ -12,7 +15,8 @@ cope with DSM: and CI: filename prefixes -cope with .. in filenames +cope with .. in filenames (may not be needed, remote backend does it for us, +for local backend filesystem does it for us) see 8.3.2 in UK MHEG Profile Modified: redbutton-browser/trunk/rb-browser.c =================================================================== --- redbutton-browser/trunk/rb-browser.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/rb-browser.c 2006-03-02 17:10:15 UTC (rev 10) @@ -113,7 +113,7 @@ } /* clean up */ - MHEGEngine_stop(); + MHEGEngine_fini(); return rc; } Modified: redbutton-browser/trunk/utils.c =================================================================== --- redbutton-browser/trunk/utils.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/utils.c 2006-03-02 17:10:15 UTC (rev 10) @@ -20,14 +20,57 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <string.h> #include <ctype.h> +#include <errno.h> #include "utils.h" /* + * write the given string (ie upto \0) to the given fd + */ + +void +write_string(int fd, const char *str) +{ + write_all(fd, str, strlen(str)); + + return; +} + +/* + * guarantee writing count bytes from buf to fd + * W. Richard Stevens + */ + +void +write_all(int fd, const void *buf, size_t count) +{ + size_t nwritten; + const char *buf_ptr; + + buf_ptr = buf; + while(count > 0) + { + if((nwritten = write(fd, buf_ptr, count)) < 0) + { + if(errno == EINTR || errno == EAGAIN) + nwritten = 0; + else + fatal("write: %s\n", strerror(errno)); + } + count -= nwritten; + buf_ptr += nwritten; + } + + return; +} + +/* * returns 15 for 'f' etc */ @@ -38,7 +81,7 @@ return 0; else if(c >= '0' && c <= '9') return c - '0'; - else + else return 10 + (tolower(c) - 'a'); } Modified: redbutton-browser/trunk/utils.h =================================================================== --- redbutton-browser/trunk/utils.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/utils.h 2006-03-02 17:10:15 UTC (rev 10) @@ -33,6 +33,9 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif +void write_string(int, const char *); +void write_all(int, const void *, size_t); + unsigned int char2hex(unsigned char); int next_utf8(unsigned char *, int, int *); Modified: redbutton-download/trunk/listen.c =================================================================== --- redbutton-download/trunk/listen.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-download/trunk/listen.c 2006-03-02 17:10:15 UTC (rev 10) @@ -192,8 +192,9 @@ quit = handle_connection(listen_data, accept_sock, &client_addr); close(accept_sock); /* TODO */ -if(quit) printf("QUIT!!!\n"); - exit(EXIT_SUCCESS); +if(quit) printf("TODO: QUIT\n"); + /* use _exit in child so stdio etc don't clean up twice */ + _exit(EXIT_SUCCESS); } else { @@ -226,7 +227,7 @@ { /* \0 terminate the buffer */ cmd[nread] = '\0'; - /* strip off an trailing \n (only needed when testing with telnet etc) */ + /* strip off any trailing \n */ nread --; while(nread > 0 && (cmd[nread] == '\n' || cmd[nread] == '\r')) cmd[nread--] = '\0'; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |