Cycles: Fix for typo in previous commit
[blender.git] / intern / cycles / device / device_network.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "device.h"
18 #include "device_intern.h"
19 #include "device_network.h"
20
21 #include "util_foreach.h"
22 #include "util_logging.h"
23
24 #if defined(WITH_NETWORK)
25
26 CCL_NAMESPACE_BEGIN
27
28 typedef map<device_ptr, device_ptr> PtrMap;
29 typedef vector<uint8_t> DataVector;
30 typedef map<device_ptr, DataVector> DataMap;
31
32 /* tile list */
33 typedef vector<RenderTile> TileList;
34
35 /* search a list of tiles and find the one that matches the passed render tile */
36 static TileList::iterator tile_list_find(TileList& tile_list, RenderTile& tile)
37 {
38         for(TileList::iterator it = tile_list.begin(); it != tile_list.end(); ++it)
39                 if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample)
40                         return it;
41         return tile_list.end();
42 }
43
44 class NetworkDevice : public Device
45 {
46 public:
47         boost::asio::io_service io_service;
48         tcp::socket socket;
49         device_ptr mem_counter;
50         DeviceTask the_task; /* todo: handle multiple tasks */
51
52         thread_mutex rpc_lock;
53
54         NetworkDevice(DeviceInfo& info, Stats &stats, const char *address)
55         : Device(info, stats, true), socket(io_service)
56         {
57                 error_func = NetworkError();
58                 stringstream portstr;
59                 portstr << SERVER_PORT;
60
61                 tcp::resolver resolver(io_service);
62                 tcp::resolver::query query(address, portstr.str());
63                 tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
64                 tcp::resolver::iterator end;
65
66                 boost::system::error_code error = boost::asio::error::host_not_found;
67                 while(error && endpoint_iterator != end)
68                 {
69                         socket.close();
70                         socket.connect(*endpoint_iterator++, error);
71                 }
72
73                 if(error)
74                         error_func.network_error(error.message());
75
76                 mem_counter = 0;
77         }
78
79         ~NetworkDevice()
80         {
81                 RPCSend snd(socket, &error_func, "stop");
82                 snd.write();
83         }
84
85         void mem_alloc(device_memory& mem, MemoryType type)
86         {
87                 thread_scoped_lock lock(rpc_lock);
88
89                 mem.device_pointer = ++mem_counter;
90
91                 RPCSend snd(socket, &error_func, "mem_alloc");
92
93                 snd.add(mem);
94                 snd.add(type);
95                 snd.write();
96         }
97
98         void mem_copy_to(device_memory& mem)
99         {
100                 thread_scoped_lock lock(rpc_lock);
101
102                 RPCSend snd(socket, &error_func, "mem_copy_to");
103
104                 snd.add(mem);
105                 snd.write();
106                 snd.write_buffer((void*)mem.data_pointer, mem.memory_size());
107         }
108
109         void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
110         {
111                 thread_scoped_lock lock(rpc_lock);
112
113                 size_t data_size = mem.memory_size();
114
115                 RPCSend snd(socket, &error_func, "mem_copy_from");
116
117                 snd.add(mem);
118                 snd.add(y);
119                 snd.add(w);
120                 snd.add(h);
121                 snd.add(elem);
122                 snd.write();
123
124                 RPCReceive rcv(socket, &error_func);
125                 rcv.read_buffer((void*)mem.data_pointer, data_size);
126         }
127
128         void mem_zero(device_memory& mem)
129         {
130                 thread_scoped_lock lock(rpc_lock);
131
132                 RPCSend snd(socket, &error_func, "mem_zero");
133
134                 snd.add(mem);
135                 snd.write();
136         }
137
138         void mem_free(device_memory& mem)
139         {
140                 if(mem.device_pointer) {
141                         thread_scoped_lock lock(rpc_lock);
142
143                         RPCSend snd(socket, &error_func, "mem_free");
144
145                         snd.add(mem);
146                         snd.write();
147
148                         mem.device_pointer = 0;
149                 }
150         }
151
152         void const_copy_to(const char *name, void *host, size_t size)
153         {
154                 thread_scoped_lock lock(rpc_lock);
155
156                 RPCSend snd(socket, &error_func, "const_copy_to");
157
158                 string name_string(name);
159
160                 snd.add(name_string);
161                 snd.add(size);
162                 snd.write();
163                 snd.write_buffer(host, size);
164         }
165
166         void tex_alloc(const char *name,
167                        device_memory& mem,
168                        InterpolationType interpolation,
169                        ExtensionType extension)
170         {
171                 VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
172
173                 thread_scoped_lock lock(rpc_lock);
174
175                 mem.device_pointer = ++mem_counter;
176
177                 RPCSend snd(socket, &error_func, "tex_alloc");
178
179                 string name_string(name);
180
181                 snd.add(name_string);
182                 snd.add(mem);
183                 snd.add(interpolation);
184                 snd.add(extension);
185                 snd.write();
186                 snd.write_buffer((void*)mem.data_pointer, mem.memory_size());
187         }
188
189         void tex_free(device_memory& mem)
190         {
191                 if(mem.device_pointer) {
192                         thread_scoped_lock lock(rpc_lock);
193
194                         RPCSend snd(socket, &error_func, "tex_free");
195
196                         snd.add(mem);
197                         snd.write();
198
199                         mem.device_pointer = 0;
200                 }
201         }
202
203         bool load_kernels(const DeviceRequestedFeatures& requested_features)
204         {
205                 if(error_func.have_error())
206                         return false;
207
208                 thread_scoped_lock lock(rpc_lock);
209
210                 RPCSend snd(socket, &error_func, "load_kernels");
211                 snd.add(requested_features.experimental);
212                 snd.add(requested_features.max_closure);
213                 snd.add(requested_features.max_nodes_group);
214                 snd.add(requested_features.nodes_features);
215                 snd.write();
216
217                 bool result;
218                 RPCReceive rcv(socket, &error_func);
219                 rcv.read(result);
220
221                 return result;
222         }
223
224         void task_add(DeviceTask& task)
225         {
226                 thread_scoped_lock lock(rpc_lock);
227
228                 the_task = task;
229
230                 RPCSend snd(socket, &error_func, "task_add");
231                 snd.add(task);
232                 snd.write();
233         }
234
235         void task_wait()
236         {
237                 thread_scoped_lock lock(rpc_lock);
238
239                 RPCSend snd(socket, &error_func, "task_wait");
240                 snd.write();
241
242                 lock.unlock();
243
244                 TileList the_tiles;
245
246                 /* todo: run this threaded for connecting to multiple clients */
247                 for(;;) {
248                         if(error_func.have_error())
249                                 break;
250
251                         RenderTile tile;
252
253                         lock.lock();
254                         RPCReceive rcv(socket, &error_func);
255
256                         if(rcv.name == "acquire_tile") {
257                                 lock.unlock();
258
259                                 /* todo: watch out for recursive calls! */
260                                 if(the_task.acquire_tile(this, tile)) { /* write return as bool */
261                                         the_tiles.push_back(tile);
262
263                                         lock.lock();
264                                         RPCSend snd(socket, &error_func, "acquire_tile");
265                                         snd.add(tile);
266                                         snd.write();
267                                         lock.unlock();
268                                 }
269                                 else {
270                                         lock.lock();
271                                         RPCSend snd(socket, &error_func, "acquire_tile_none");
272                                         snd.write();
273                                         lock.unlock();
274                                 }
275                         }
276                         else if(rcv.name == "release_tile") {
277                                 rcv.read(tile);
278                                 lock.unlock();
279
280                                 TileList::iterator it = tile_list_find(the_tiles, tile);
281                                 if(it != the_tiles.end()) {
282                                         tile.buffers = it->buffers;
283                                         the_tiles.erase(it);
284                                 }
285
286                                 assert(tile.buffers != NULL);
287
288                                 the_task.release_tile(tile);
289
290                                 lock.lock();
291                                 RPCSend snd(socket, &error_func, "release_tile");
292                                 snd.write();
293                                 lock.unlock();
294                         }
295                         else if(rcv.name == "task_wait_done") {
296                                 lock.unlock();
297                                 break;
298                         }
299                         else
300                                 lock.unlock();
301                 }
302         }
303
304         void task_cancel()
305         {
306                 thread_scoped_lock lock(rpc_lock);
307                 RPCSend snd(socket, &error_func, "task_cancel");
308                 snd.write();
309         }
310
311         int get_split_task_count(DeviceTask& task)
312         {
313                 return 1;
314         }
315
316 private:
317         NetworkError error_func;
318 };
319
320 Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address)
321 {
322         return new NetworkDevice(info, stats, address);
323 }
324
325 void device_network_info(vector<DeviceInfo>& devices)
326 {
327         DeviceInfo info;
328
329         info.type = DEVICE_NETWORK;
330         info.description = "Network Device";
331         info.id = "NETWORK";
332         info.num = 0;
333         info.advanced_shading = true; /* todo: get this info from device */
334         info.pack_images = false;
335
336         devices.push_back(info);
337 }
338
339 class DeviceServer {
340 public:
341         thread_mutex rpc_lock;
342
343         void network_error(const string &message) {
344                 error_func.network_error(message);
345         }
346
347         bool have_error() { return error_func.have_error(); }
348
349         DeviceServer(Device *device_, tcp::socket& socket_)
350         : device(device_), socket(socket_), stop(false), blocked_waiting(false)
351         {
352                 error_func = NetworkError();
353         }
354
355         void listen()
356         {
357                 /* receive remote function calls */
358                 for(;;) {
359                         listen_step();
360
361                         if(stop)
362                                 break;
363                 }
364         }
365
366 protected:
367         void listen_step()
368         {
369                 thread_scoped_lock lock(rpc_lock);
370                 RPCReceive rcv(socket, &error_func);
371
372                 if(rcv.name == "stop")
373                         stop = true;
374                 else
375                         process(rcv, lock);
376         }
377
378         /* create a memory buffer for a device buffer and insert it into mem_data */
379         DataVector &data_vector_insert(device_ptr client_pointer, size_t data_size)
380         {
381                 /* create a new DataVector and insert it into mem_data */
382                 pair<DataMap::iterator,bool> data_ins = mem_data.insert(
383                         DataMap::value_type(client_pointer, DataVector()));
384
385                 /* make sure it was a unique insertion */
386                 assert(data_ins.second);
387
388                 /* get a reference to the inserted vector */
389                 DataVector &data_v = data_ins.first->second;
390
391                 /* size the vector */
392                 data_v.resize(data_size);
393
394                 return data_v;
395         }
396
397         DataVector &data_vector_find(device_ptr client_pointer)
398         {
399                 DataMap::iterator i = mem_data.find(client_pointer);
400                 assert(i != mem_data.end());
401                 return i->second;
402         }
403
404         /* setup mapping and reverse mapping of client_pointer<->real_pointer */
405         void pointer_mapping_insert(device_ptr client_pointer, device_ptr real_pointer)
406         {
407                 pair<PtrMap::iterator,bool> mapins;
408
409                 /* insert mapping from client pointer to our real device pointer */
410                 mapins = ptr_map.insert(PtrMap::value_type(client_pointer, real_pointer));
411                 assert(mapins.second);
412
413                 /* insert reverse mapping from real our device pointer to client pointer */
414                 mapins = ptr_imap.insert(PtrMap::value_type(real_pointer, client_pointer));
415                 assert(mapins.second);
416         }
417
418         device_ptr device_ptr_from_client_pointer(device_ptr client_pointer)
419         {
420                 PtrMap::iterator i = ptr_map.find(client_pointer);
421                 assert(i != ptr_map.end());
422                 return i->second;
423         }
424
425         device_ptr device_ptr_from_client_pointer_erase(device_ptr client_pointer)
426         {
427                 PtrMap::iterator i = ptr_map.find(client_pointer);
428                 assert(i != ptr_map.end());
429
430                 device_ptr result = i->second;
431
432                 /* erase the mapping */
433                 ptr_map.erase(i);
434
435                 /* erase the reverse mapping */
436                 PtrMap::iterator irev = ptr_imap.find(result);
437                 assert(irev != ptr_imap.end());
438                 ptr_imap.erase(irev);
439
440                 /* erase the data vector */
441                 DataMap::iterator idata = mem_data.find(client_pointer);
442                 assert(idata != mem_data.end());
443                 mem_data.erase(idata);
444
445                 return result;
446         }
447
448         /* note that the lock must be already acquired upon entry.
449          * This is necessary because the caller often peeks at
450          * the header and delegates control to here when it doesn't
451          * specifically handle the current RPC.
452          * The lock must be unlocked before returning */
453         void process(RPCReceive& rcv, thread_scoped_lock &lock)
454         {
455                 if(rcv.name == "mem_alloc") {
456                         MemoryType type;
457                         network_device_memory mem;
458                         device_ptr client_pointer;
459
460                         rcv.read(mem);
461                         rcv.read(type);
462
463                         lock.unlock();
464
465                         client_pointer = mem.device_pointer;
466
467                         /* create a memory buffer for the device buffer */
468                         size_t data_size = mem.memory_size();
469                         DataVector &data_v = data_vector_insert(client_pointer, data_size);
470
471                         if(data_size)
472                                 mem.data_pointer = (device_ptr)&(data_v[0]);
473                         else
474                                 mem.data_pointer = 0;
475
476                         /* perform the allocation on the actual device */
477                         device->mem_alloc(mem, type);
478
479                         /* store a mapping to/from client_pointer and real device pointer */
480                         pointer_mapping_insert(client_pointer, mem.device_pointer);
481                 }
482                 else if(rcv.name == "mem_copy_to") {
483                         network_device_memory mem;
484
485                         rcv.read(mem);
486                         lock.unlock();
487
488                         device_ptr client_pointer = mem.device_pointer;
489
490                         DataVector &data_v = data_vector_find(client_pointer);
491
492                         size_t data_size = mem.memory_size();
493
494                         /* get pointer to memory buffer for device buffer */
495                         mem.data_pointer = (device_ptr)&data_v[0];
496
497                         /* copy data from network into memory buffer */
498                         rcv.read_buffer((uint8_t*)mem.data_pointer, data_size);
499
500                         /* translate the client pointer to a real device pointer */
501                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
502
503                         /* copy the data from the memory buffer to the device buffer */
504                         device->mem_copy_to(mem);
505                 }
506                 else if(rcv.name == "mem_copy_from") {
507                         network_device_memory mem;
508                         int y, w, h, elem;
509
510                         rcv.read(mem);
511                         rcv.read(y);
512                         rcv.read(w);
513                         rcv.read(h);
514                         rcv.read(elem);
515
516                         device_ptr client_pointer = mem.device_pointer;
517                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
518
519                         DataVector &data_v = data_vector_find(client_pointer);
520
521                         mem.data_pointer = (device_ptr)&(data_v[0]);
522
523                         device->mem_copy_from(mem, y, w, h, elem);
524
525                         size_t data_size = mem.memory_size();
526
527                         RPCSend snd(socket, &error_func, "mem_copy_from");
528                         snd.write();
529                         snd.write_buffer((uint8_t*)mem.data_pointer, data_size);
530                         lock.unlock();
531                 }
532                 else if(rcv.name == "mem_zero") {
533                         network_device_memory mem;
534                         
535                         rcv.read(mem);
536                         lock.unlock();
537
538                         device_ptr client_pointer = mem.device_pointer;
539                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
540
541                         DataVector &data_v = data_vector_find(client_pointer);
542
543                         mem.data_pointer = (device_ptr)&(data_v[0]);
544
545                         device->mem_zero(mem);
546                 }
547                 else if(rcv.name == "mem_free") {
548                         network_device_memory mem;
549                         device_ptr client_pointer;
550
551                         rcv.read(mem);
552                         lock.unlock();
553
554                         client_pointer = mem.device_pointer;
555
556                         mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer);
557
558                         device->mem_free(mem);
559                 }
560                 else if(rcv.name == "const_copy_to") {
561                         string name_string;
562                         size_t size;
563
564                         rcv.read(name_string);
565                         rcv.read(size);
566
567                         vector<char> host_vector(size);
568                         rcv.read_buffer(&host_vector[0], size);
569                         lock.unlock();
570
571                         device->const_copy_to(name_string.c_str(), &host_vector[0], size);
572                 }
573                 else if(rcv.name == "tex_alloc") {
574                         network_device_memory mem;
575                         string name;
576                         InterpolationType interpolation;
577                         ExtensionType extension_type;
578                         device_ptr client_pointer;
579
580                         rcv.read(name);
581                         rcv.read(mem);
582                         rcv.read(interpolation);
583                         rcv.read(extension_type);
584                         lock.unlock();
585
586                         client_pointer = mem.device_pointer;
587
588                         size_t data_size = mem.memory_size();
589
590                         DataVector &data_v = data_vector_insert(client_pointer, data_size);
591
592                         if(data_size)
593                                 mem.data_pointer = (device_ptr)&(data_v[0]);
594                         else
595                                 mem.data_pointer = 0;
596
597                         rcv.read_buffer((uint8_t*)mem.data_pointer, data_size);
598
599                         device->tex_alloc(name.c_str(), mem, interpolation, extension_type);
600
601                         pointer_mapping_insert(client_pointer, mem.device_pointer);
602                 }
603                 else if(rcv.name == "tex_free") {
604                         network_device_memory mem;
605                         device_ptr client_pointer;
606
607                         rcv.read(mem);
608                         lock.unlock();
609
610                         client_pointer = mem.device_pointer;
611
612                         mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer);
613
614                         device->tex_free(mem);
615                 }
616                 else if(rcv.name == "load_kernels") {
617                         DeviceRequestedFeatures requested_features;
618                         rcv.read(requested_features.experimental);
619                         rcv.read(requested_features.max_closure);
620                         rcv.read(requested_features.max_nodes_group);
621                         rcv.read(requested_features.nodes_features);
622
623                         bool result;
624                         result = device->load_kernels(requested_features);
625                         RPCSend snd(socket, &error_func, "load_kernels");
626                         snd.add(result);
627                         snd.write();
628                         lock.unlock();
629                 }
630                 else if(rcv.name == "task_add") {
631                         DeviceTask task;
632
633                         rcv.read(task);
634                         lock.unlock();
635
636                         if(task.buffer)
637                                 task.buffer = device_ptr_from_client_pointer(task.buffer);
638
639                         if(task.rgba_half)
640                                 task.rgba_half = device_ptr_from_client_pointer(task.rgba_half);
641
642                         if(task.rgba_byte)
643                                 task.rgba_byte = device_ptr_from_client_pointer(task.rgba_byte);
644
645                         if(task.shader_input)
646                                 task.shader_input = device_ptr_from_client_pointer(task.shader_input);
647
648                         if(task.shader_output)
649                                 task.shader_output = device_ptr_from_client_pointer(task.shader_output);
650
651
652                         task.acquire_tile = function_bind(&DeviceServer::task_acquire_tile, this, _1, _2);
653                         task.release_tile = function_bind(&DeviceServer::task_release_tile, this, _1);
654                         task.update_progress_sample = function_bind(&DeviceServer::task_update_progress_sample, this);
655                         task.update_tile_sample = function_bind(&DeviceServer::task_update_tile_sample, this, _1);
656                         task.get_cancel = function_bind(&DeviceServer::task_get_cancel, this);
657
658                         device->task_add(task);
659                 }
660                 else if(rcv.name == "task_wait") {
661                         lock.unlock();
662
663                         blocked_waiting = true;
664                         device->task_wait();
665                         blocked_waiting = false;
666
667                         lock.lock();
668                         RPCSend snd(socket, &error_func, "task_wait_done");
669                         snd.write();
670                         lock.unlock();
671                 }
672                 else if(rcv.name == "task_cancel") {
673                         lock.unlock();
674                         device->task_cancel();
675                 }
676                 else if(rcv.name == "acquire_tile") {
677                         AcquireEntry entry;
678                         entry.name = rcv.name;
679                         rcv.read(entry.tile);
680                         acquire_queue.push_back(entry);
681                         lock.unlock();
682                 }
683                 else if(rcv.name == "acquire_tile_none") {
684                         AcquireEntry entry;
685                         entry.name = rcv.name;
686                         acquire_queue.push_back(entry);
687                         lock.unlock();
688                 }
689                 else if(rcv.name == "release_tile") {
690                         AcquireEntry entry;
691                         entry.name = rcv.name;
692                         acquire_queue.push_back(entry);
693                         lock.unlock();
694                 }
695                 else {
696                         cout << "Error: unexpected RPC receive call \"" + rcv.name + "\"\n";
697                         lock.unlock();
698                 }
699         }
700
701         bool task_acquire_tile(Device *device, RenderTile& tile)
702         {
703                 thread_scoped_lock acquire_lock(acquire_mutex);
704
705                 bool result = false;
706
707                 RPCSend snd(socket, &error_func, "acquire_tile");
708                 snd.write();
709
710                 do {
711                         if(blocked_waiting)
712                                 listen_step();
713
714                         /* todo: avoid busy wait loop */
715                         thread_scoped_lock lock(rpc_lock);
716
717                         if(!acquire_queue.empty()) {
718                                 AcquireEntry entry = acquire_queue.front();
719                                 acquire_queue.pop_front();
720
721                                 if(entry.name == "acquire_tile") {
722                                         tile = entry.tile;
723
724                                         if(tile.buffer) tile.buffer = ptr_map[tile.buffer];
725                                         if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state];
726
727                                         result = true;
728                                         break;
729                                 }
730                                 else if(entry.name == "acquire_tile_none") {
731                                         break;
732                                 }
733                                 else {
734                                         cout << "Error: unexpected acquire RPC receive call \"" + entry.name + "\"\n";
735                                 }
736                         }
737                 } while(acquire_queue.empty() && !stop && !have_error());
738
739                 return result;
740         }
741
742         void task_update_progress_sample()
743         {
744                 ; /* skip */
745         }
746
747         void task_update_tile_sample(RenderTile&)
748         {
749                 ; /* skip */
750         }
751
752         void task_release_tile(RenderTile& tile)
753         {
754                 thread_scoped_lock acquire_lock(acquire_mutex);
755
756                 if(tile.buffer) tile.buffer = ptr_imap[tile.buffer];
757                 if(tile.rng_state) tile.rng_state = ptr_imap[tile.rng_state];
758
759                 {
760                         thread_scoped_lock lock(rpc_lock);
761                         RPCSend snd(socket, &error_func, "release_tile");
762                         snd.add(tile);
763                         snd.write();
764                         lock.unlock();
765                 }
766
767                 do {
768                         if(blocked_waiting)
769                                 listen_step();
770
771                         /* todo: avoid busy wait loop */
772                         thread_scoped_lock lock(rpc_lock);
773
774                         if(!acquire_queue.empty()) {
775                                 AcquireEntry entry = acquire_queue.front();
776                                 acquire_queue.pop_front();
777
778                                 if(entry.name == "release_tile") {
779                                         lock.unlock();
780                                         break;
781                                 }
782                                 else {
783                                         cout << "Error: unexpected release RPC receive call \"" + entry.name + "\"\n";
784                                 }
785                         }
786                 } while(acquire_queue.empty() && !stop);
787         }
788
789         bool task_get_cancel()
790         {
791                 return false;
792         }
793
794         /* properties */
795         Device *device;
796         tcp::socket& socket;
797
798         /* mapping of remote to local pointer */
799         PtrMap ptr_map;
800         PtrMap ptr_imap;
801         DataMap mem_data;
802
803         struct AcquireEntry {
804                 string name;
805                 RenderTile tile;
806         };
807
808         thread_mutex acquire_mutex;
809         list<AcquireEntry> acquire_queue;
810
811         bool stop;
812         bool blocked_waiting;
813 private:
814         NetworkError error_func;
815
816         /* todo: free memory and device (osl) on network error */
817
818 };
819
820 void Device::server_run()
821 {
822         try {
823                 /* starts thread that responds to discovery requests */
824                 ServerDiscovery discovery;
825
826                 for(;;) {
827                         /* accept connection */
828                         boost::asio::io_service io_service;
829                         tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), SERVER_PORT));
830
831                         tcp::socket socket(io_service);
832                         acceptor.accept(socket);
833
834                         string remote_address = socket.remote_endpoint().address().to_string();
835                         printf("Connected to remote client at: %s\n", remote_address.c_str());
836
837                         DeviceServer server(this, socket);
838                         server.listen();
839
840                         printf("Disconnected.\n");
841                 }
842         }
843         catch(exception& e) {
844                 fprintf(stderr, "Network server exception: %s\n", e.what());
845         }
846 }
847
848 CCL_NAMESPACE_END
849
850 #endif
851
852