storage_server.c from EmStar at Krugle
Show storage_server.c syntax highlighted
/*
*
* Copyright (c) 2006 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR
* CONTRIBUTORS 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.
*
*/
/*
* server to save to a remote device
*/
#include <include/remote.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <signal.h>
#include <sys/wait.h>
#define DEBUG(args...)
//#define DEBUG(args...) syslog(args)
#define OPTS_DELIM ",\n:"
static
void sig_child(int signal)
{
int status;
int pid = waitpid(-1, &status, WNOHANG);
if (pid > 0) {
DEBUG(LOG_NOTICE, "child process %d completed: %d",
pid, status);
}
}
void handle_connection(int sock)
{
int append = 0;
int wavpack = 0;
FILE *f = fdopen(sock, "w+");
/* OK, read in the filename to save to */
char filename[512];
filename[0] = 0;
if (fgets(filename, sizeof(filename), f) == NULL ||
filename[strlen(filename)-1] != '\n') {
syslog(LOG_WARNING, "filename read failed (%s): %m", filename);
exit(1);
}
char opts[512];
opts[0] = 0;
if (fgets(opts, sizeof(opts), f) == NULL ||
opts[strlen(opts)-1] != '\n') {
syslog(LOG_WARNING, "opts read failed (%s): %m", opts);
exit(1);
}
/* parse options */
char *tmp = opts;
char *item;
while ((item = strtok(tmp, OPTS_DELIM))) {
tmp = NULL;
if (strcmp(item, "append") == 0)
append = 1;
if (strcmp(item, "wavpack") == 0)
wavpack = 1;
}
if (strncmp(filename, "/remote/", 8)) {
syslog(LOG_NOTICE, "Expected fn to start with remote: '%s'", filename);
exit(1);
}
memmove(filename, "/mnt/cf/", 8);
filename[strlen(filename)-1] = 0;
if (append)
DEBUG(LOG_NOTICE, "Writing to new file %s", filename);
else
syslog(LOG_NOTICE, "Writing to new file %s", filename);
char rpath[512];
realpath(filename, rpath);
char *rpath2 = strdup(rpath);
char *path = dirname(rpath2);
/* create dir if needed */
char cmd[512];
sprintf(cmd, "mkdir -p %s", path);
system(cmd);
/* open the file */
FILE *out = fopen(rpath, append ? "a" : "w");
if (out == NULL) {
syslog(LOG_CRIT, "unable to open new file %s", rpath);
exit(1);
}
DEBUG(LOG_NOTICE, "opened file");
while (1) {
char chunk[16384];
int status = fread(chunk, 1, sizeof(chunk), f);
if (status == sizeof(chunk)) {
int stat2 = fwrite(chunk, 1, status, out);
if (stat2 != status) {
if (ferror(out)) {
syslog(LOG_CRIT, "error writing file '%s': %m", rpath);
break;
}
syslog(LOG_CRIT, "eof writing file '%s'??: %m", rpath);
break;
}
/* $$ write back progress report?? */
}
else {
if (ferror(f)) {
syslog(LOG_CRIT, "error reading file '%s': %m", rpath);
}
break;
}
}
fclose(out);
fclose(f);
if (append)
DEBUG(LOG_NOTICE, "completed write of file '%s': %m", rpath);
else
syslog(LOG_NOTICE, "completed write of file '%s': %m", rpath);
sync();
DEBUG(LOG_NOTICE, "synced");
}
int main(int argc, char *argv[])
{
signal(SIGCHLD, sig_child);
/* address to bind to */
struct sockaddr_in saddr = {
sin_family: AF_INET,
sin_port: htons(STORAGE_SERVER_PORT),
sin_addr: {
s_addr: INADDR_ANY
}
};
int status;
int sock;
int val = 1;
int lq;
openlog("remote_save", LOG_PERROR, LOG_DAEMON);
syslog(LOG_NOTICE, "Starting up");
/* get a socket */
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
syslog(LOG_CRIT, "Socket call failed: %m");
exit(1);
}
/* configure the socket */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
syslog(LOG_WARNING, "Unable to set SO_REUSEADDR on server socket, continuing: %m");
}
/* try to bind */
status = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (status < 0) {
syslog(LOG_CRIT, "Unable to bind to port %d: %m", STORAGE_SERVER_PORT);
exit(1);
}
/* listen */
lq = 100;
if (listen(sock, lq) < 0) {
syslog(LOG_CRIT, "Unable to listen, queue %d: %m", lq);
exit(1);
}
while (1) {
/* now wait for a connection */
DEBUG(LOG_NOTICE, "Waiting for a connection.");
struct sockaddr_in saddr;
size_t size = sizeof(saddr);
int sock2 = accept(sock, (struct sockaddr *)&saddr, &size);
if (sock2 < 0) {
syslog(LOG_CRIT, "Accept returned error: %m");
exit(1);
}
/* ok, now fork */
int childpid = fork();
if (childpid < 0) {
syslog(LOG_CRIT, "Fork failed: %m");
exit(1);
}
if (childpid) {
close(sock2);
}
else {
handle_connection(sock2);
exit(0);
}
}
}
See more files for this project here