-rw-r--r-- | src/eyefiservice.cc | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/eyefiservice.cc b/src/eyefiservice.cc new file mode 100644 index 0000000..30c06fa --- a/dev/null +++ b/src/eyefiservice.cc | |||
@@ -0,0 +1,186 @@ | |||
1 | #include <cassert> | ||
2 | #include <iostream> | ||
3 | #include <fstream> | ||
4 | #include <stdexcept> | ||
5 | #include <iterator> | ||
6 | #include <syslog.h> | ||
7 | #include <sys/wait.h> | ||
8 | #include <autosprintf.h> | ||
9 | #include "eyekinfig.h" | ||
10 | #include "eyetil.h" | ||
11 | #include "soapeyefiService.h" | ||
12 | |||
13 | static bool detached_child() { | ||
14 | pid_t p = fork(); | ||
15 | if(p<0) throw std::runtime_error("failed to fork()"); | ||
16 | if(!p) { | ||
17 | p = fork(); | ||
18 | if(p<0) { | ||
19 | syslog(LOG_ERR,"Failed to re-fork child process"); | ||
20 | _exit(-1); | ||
21 | } | ||
22 | if(!p) { | ||
23 | setsid(); | ||
24 | for(int i=getdtablesize();i>=0;--i) close(i); | ||
25 | int i=open("/dev/null",O_RDWR); assert(i==0); | ||
26 | i = dup(i); assert(i==1); | ||
27 | i = dup(i); assert(i==2); | ||
28 | return true; | ||
29 | } | ||
30 | _exit(0); | ||
31 | } | ||
32 | int rc; | ||
33 | if(waitpid(p,&rc,0)<0) throw std::runtime_error("failed to waitpid()"); | ||
34 | if(!WIFEXITED(rc)) throw std::runtime_error("error in forked process"); | ||
35 | if(WEXITSTATUS(rc)) throw std::runtime_error("forked process signalled error"); | ||
36 | return false; | ||
37 | } | ||
38 | |||
39 | int eyefiService::StartSession( | ||
40 | std::string macaddress,std::string cnonce, | ||
41 | int transfermode,long transfermodetimestamp, | ||
42 | struct rns__StartSessionResponse &r ) { | ||
43 | #ifndef NDEBUG | ||
44 | syslog(LOG_DEBUG, | ||
45 | "StartSession request from %s with cnonce=%s, transfermode=%d, transfermodetimestamp=%ld", | ||
46 | macaddress.c_str(), cnonce.c_str(), transfermode, transfermodetimestamp ); | ||
47 | #endif | ||
48 | r.credential = binary_t(macaddress+cnonce+eyekinfig_t(macaddress).get_upload_key()).md5().hex(); | ||
49 | /* TODO: better nonce generator */ | ||
50 | time_t t = time(0); | ||
51 | r.snonce = binary_t(&t,sizeof(t)).md5().hex(); | ||
52 | r.transfermode=2; | ||
53 | r.transfermodetimestamp=t; | ||
54 | r.upsyncallowed=false; | ||
55 | |||
56 | std::string cmd = eyekinfig_t(macaddress).get_on_start_session(); | ||
57 | if(!cmd.empty()) { | ||
58 | if(detached_child()) { | ||
59 | putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) ); | ||
60 | putenv( gnu::autosprintf("EYEFI_TRANSFERMODE=%d",transfermode) ); | ||
61 | putenv( gnu::autosprintf("EYEFI_TRANSFERMODETIMESTAMP=%ld",transfermodetimestamp) ); | ||
62 | char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 }; | ||
63 | execv("/bin/sh",argv); | ||
64 | syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str()); | ||
65 | _exit(-1); | ||
66 | } | ||
67 | } | ||
68 | return SOAP_OK; | ||
69 | } | ||
70 | |||
71 | int eyefiService::GetPhotoStatus( | ||
72 | std::string credential, std::string macaddress, | ||
73 | std::string filename, long filesize, std::string filesignature, | ||
74 | struct rns__GetPhotoStatusResponse &r ) { | ||
75 | #ifndef NDEBUG | ||
76 | syslog(LOG_DEBUG, | ||
77 | "GetPhotoStatus request from %s with credential=%s, filename=%s, filesize=%ld, filesignature=%s", | ||
78 | macaddress.c_str(), credential.c_str(), filename.c_str(), filesize, filesignature.c_str() ); | ||
79 | #endif | ||
80 | r.fileid = 1; r.offset = 0; | ||
81 | return SOAP_OK; | ||
82 | } | ||
83 | |||
84 | int eyefiService::MarkLastPhotoInRoll( | ||
85 | std::string macaddress, int mergedelta, | ||
86 | struct rns__MarkLastPhotoInRollResponse &r ) { | ||
87 | #ifndef NDEBUG | ||
88 | syslog(LOG_DEBUG, | ||
89 | "MarkLastPhotoInRoll request from %s with mergedelta=%d", | ||
90 | macaddress.c_str(), mergedelta ); | ||
91 | #endif | ||
92 | std::string cmd = eyekinfig_t(macaddress).get_on_mark_last_photo_in_roll(); | ||
93 | if(!cmd.empty()) { | ||
94 | if(detached_child()) { | ||
95 | putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) ); | ||
96 | putenv( gnu::autosprintf("EYEFI_MERGEDELTA=%d",mergedelta) ); | ||
97 | char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 }; | ||
98 | execv("/bin/sh",argv); | ||
99 | syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str()); | ||
100 | _exit(-1); | ||
101 | } | ||
102 | } | ||
103 | return SOAP_OK; | ||
104 | } | ||
105 | |||
106 | int eyefiService::UploadPhoto( | ||
107 | int fileid, std::string macaddress, | ||
108 | std::string filename, long filesize, std::string filesignature, | ||
109 | std::string encryption, int flags, | ||
110 | struct rns__UploadPhotoResponse& r ) { | ||
111 | #ifndef NDEBUG | ||
112 | syslog(LOG_DEBUG, | ||
113 | "UploadPhoto request from %s with fileid=%d, filename=%s, filesize=%ld," | ||
114 | " filesignature=%s, encryption=%s, flags=%04X", | ||
115 | macaddress.c_str(), fileid, filename.c_str(), filesize, | ||
116 | filesignature.c_str(), encryption.c_str(), flags ); | ||
117 | #endif | ||
118 | eyekinfig_t eyekinfig(macaddress); | ||
119 | |||
120 | umask(eyekinfig.get_umask()); | ||
121 | |||
122 | std::string td = eyekinfig.get_targetdir(); | ||
123 | /* TODO: try to create, if needed */ | ||
124 | tmpdir_t indir(td+"/.incoming.XXXXXX"); | ||
125 | |||
126 | for(soap_multipart::iterator i=mime.begin(),ie=mime.end();i!=ie;++i) { | ||
127 | #ifndef NDEBUG | ||
128 | syslog(LOG_DEBUG, | ||
129 | " MIME attachment with id=%s, type=%s, size=%ld", | ||
130 | (*i).id, (*i).type, (long)(*i).size ); | ||
131 | #endif | ||
132 | |||
133 | #ifndef NDEBUG | ||
134 | if((*i).id && !strcmp((*i).id,"INTEGRITYDIGEST")) { | ||
135 | std::string idigest((*i).ptr,(*i).size); | ||
136 | syslog(LOG_DEBUG, " INTEGRITYDIGEST=%s", idigest.c_str()); | ||
137 | } | ||
138 | #endif | ||
139 | if( (*i).id && !strcmp((*i).id,"FILENAME") ) { | ||
140 | assert( (*i).type && !strcmp((*i).type,"application/x-tar") ); | ||
141 | #ifdef III_SAVE_TARS | ||
142 | std::string tarfile = indir.get_file(filename); | ||
143 | { | ||
144 | std::ofstream(tarfile.c_str(),std::ios::out|std::ios::binary).write((*i).ptr,(*i).size); | ||
145 | } | ||
146 | #endif | ||
147 | tarchive_t a((*i).ptr,(*i).size); | ||
148 | if(!a.read_next_header()) | ||
149 | throw std::runtime_error("failed to tarchive_t::read_next_header())"); | ||
150 | std::string jf = indir.get_file(a.entry_pathname()); | ||
151 | std::string::size_type ls = jf.rfind('/'); | ||
152 | std::string jbn = (ls==std::string::npos)?jf:jf.substr(ls+1); | ||
153 | int fd=open(jf.c_str(),O_CREAT|O_WRONLY,0666); | ||
154 | assert(fd>0); | ||
155 | a.read_data_into_fd(fd); | ||
156 | close(fd); | ||
157 | std::string tf = td+'/'+jbn; | ||
158 | bool success = false; | ||
159 | if(!link(jf.c_str(), tf.c_str())) { | ||
160 | unlink(jf.c_str()); success = true; | ||
161 | }else{ | ||
162 | for(int i=1;i<32767;++i) { | ||
163 | tf = (const char*)gnu::autosprintf( "%s/(%05d)%s", | ||
164 | td.c_str(), i, jbn.c_str() ); | ||
165 | if(!link(jf.c_str(), tf.c_str())) { | ||
166 | unlink(jf.c_str()); success = true; | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | std::string cmd = eyekinfig.get_on_upload_photo(); | ||
172 | if(success && !cmd.empty()) { | ||
173 | if(detached_child()) { | ||
174 | putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) ); | ||
175 | putenv( gnu::autosprintf("EYEFI_UPLOADED=%s",tf.c_str()) ); | ||
176 | char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 }; | ||
177 | execv("/bin/sh",argv); | ||
178 | syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str()); | ||
179 | _exit(-1); | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | r.success = true; | ||
185 | return SOAP_OK; | ||
186 | } | ||