00001 /*!@file NeovisionII/nv2_label_server.c */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/NeovisionII/nv2_label_server.c $ 00035 // $Id: nv2_label_server.c 9765 2008-05-12 16:58:24Z rjpeters $ 00036 // 00037 00038 #ifndef NEOVISIONII_NV2_LABEL_SERVER_C_DEFINED 00039 #define NEOVISIONII_NV2_LABEL_SERVER_C_DEFINED 00040 00041 #include "NeovisionII/nv2_label_server.h" 00042 00043 #include "NeovisionII/nv2_common.h" 00044 00045 // #include order matters here: 00046 #include <sys/types.h> 00047 #include <sys/socket.h> 00048 #include <netinet/in.h> 00049 #include <arpa/inet.h> 00050 00051 #include <errno.h> 00052 #include <pthread.h> 00053 #include <stdio.h> 00054 #include <stdlib.h> 00055 #include <string.h> 00056 #include <unistd.h> 00057 00058 struct nv2_label_server 00059 { 00060 pthread_mutex_t m_patch_lock; 00061 struct nv2_image_patch m_patch; 00062 int m_should_quit; 00063 00064 int m_patch_reader_port; 00065 struct in_addr m_remote_label_reader_in_addr; 00066 int m_remote_label_reader_port; 00067 00068 int m_verbosity; 00069 00070 volatile int socket_fd; 00071 00072 pthread_t m_patch_reader_thread; 00073 }; 00074 00075 static void* run_patch_reader(void* vq) 00076 { 00077 struct nv2_label_server* const q = (struct nv2_label_server*) vq; 00078 00079 q->socket_fd = socket(PF_INET, SOCK_STREAM, 0); 00080 if (q->socket_fd == -1) 00081 nv2_fatal("socket() failed"); 00082 00083 { 00084 const int set_on = 1; 00085 if (setsockopt(q->socket_fd, 00086 SOL_SOCKET, SO_REUSEADDR, 00087 &set_on, sizeof(set_on)) == -1) 00088 nv2_warn("setsockopt() failed"); 00089 } 00090 00091 struct sockaddr_in name; 00092 name.sin_family = AF_INET; 00093 name.sin_addr.s_addr = htonl(INADDR_ANY); // accept from any host 00094 name.sin_port = htons(q->m_patch_reader_port); 00095 if (bind(q->socket_fd, (struct sockaddr*)(&name), sizeof(name)) == -1) 00096 nv2_fatal("bind() failed"); 00097 00098 listen(q->socket_fd, 5); 00099 00100 int client_socket_fd = -1; 00101 00102 // Accept incoming connections 00103 while (q->socket_fd > 0) 00104 { 00105 struct sockaddr_in client_name; 00106 socklen_t client_name_len = sizeof(client_name); 00107 00108 client_socket_fd = 00109 accept(q->socket_fd, 00110 (struct sockaddr*)(&client_name), 00111 &client_name_len); 00112 00113 if (client_socket_fd < 0) 00114 { 00115 // if accept() failed because q->socket_fd was 00116 // closed() and/or is less than 0, then that 00117 // is because the main thread closed the 00118 // socket to force us to shut down, so let's 00119 // quit without any nv2_warn() 00120 if (q->socket_fd < 0) 00121 break; 00122 00123 if (q->m_verbosity >= 1) 00124 fprintf(stderr, "accept() failed " 00125 "(strerror=%s)\n", 00126 strerror(errno)); 00127 continue; 00128 } 00129 00130 struct nv2_image_patch p; 00131 nv2_image_patch_init_empty(&p); 00132 00133 if (nv2_robust_read(client_socket_fd, &p, 00134 NV2_IMAGE_PATCH_HEADER_SIZE, NULL) 00135 != NV2_IMAGE_PATCH_HEADER_SIZE) 00136 { 00137 if (q->m_verbosity >= 1) 00138 fprintf(stderr, "read(header) failed\n"); 00139 break; 00140 } 00141 00142 p.protocol_version = ntohl(p.protocol_version); 00143 p.width = ntohl(p.width); 00144 p.height = ntohl(p.height); 00145 p.id = ntohl(p.id); 00146 p.is_training_image= ntohl(p.is_training_image); 00147 p.type = ntohl(p.type); 00148 p.training_label[sizeof(p.training_label)-1] = '\0'; 00149 p.remote_command[sizeof(p.remote_command)-1] = '\0'; 00150 00151 const uint32_t npixbytes = 00152 p.width * p.height * nv2_pixel_type_bytes_per_pixel(p.type); 00153 00154 // set a maximum image size of 16MB, so that we avoid 00155 // trying to allocate too much memory when filling in 00156 // the pixel array 00157 const uint32_t maxbytes = 4096*4096; 00158 00159 int doquit = 0; 00160 00161 if (npixbytes > maxbytes) 00162 { 00163 if (q->m_verbosity >= 1) 00164 fprintf(stderr, 00165 "image patch was %ux%u%u=%u bytes, " 00166 "but the maximum allowable size " 00167 "is %u bytes\n", 00168 (unsigned int) p.width, 00169 (unsigned int) p.height, 00170 (unsigned int) nv2_pixel_type_bytes_per_pixel(p.type), 00171 (unsigned int) npixbytes, 00172 (unsigned int) maxbytes); 00173 00174 doquit = 1; 00175 } 00176 else if (p.protocol_version == 0) 00177 { 00178 // client will send protocol_version == 0 to 00179 // tell us to quit: 00180 doquit = 1; 00181 } 00182 else if (p.protocol_version != NV2_PATCH_PROTOCOL_VERSION) 00183 { 00184 if (q->m_verbosity >= 1) 00185 fprintf(stderr, 00186 "wrong patch protocol version " 00187 "(got %u, expected %u)", 00188 (unsigned int) p.protocol_version, 00189 (unsigned int) NV2_PATCH_PROTOCOL_VERSION); 00190 00191 doquit = 1; 00192 } 00193 else 00194 { 00195 p.data = (unsigned char*) malloc(npixbytes); 00196 00197 int nchunks_read = 0; 00198 00199 const size_t n = 00200 nv2_robust_read(client_socket_fd, 00201 p.data, npixbytes, 00202 &nchunks_read); 00203 00204 if (n != npixbytes) 00205 { 00206 doquit = 1; 00207 if (q->m_verbosity >= 1) 00208 nv2_warn("read(pixels) failed"); 00209 } 00210 00211 if (q->m_verbosity >= 2) 00212 fprintf(stderr, 00213 "got patch = { .protocol_version=%u, " 00214 ".width=%u, .height=%u, .id=%u, " 00215 ".is_training=%u, " 00216 ".label='%s', .cmd='%s', " 00217 ".data=[%d bytes in %d chunks] }\n", 00218 (unsigned int) p.protocol_version, 00219 (unsigned int) p.width, 00220 (unsigned int) p.height, 00221 (unsigned int) p.id, 00222 (unsigned int) p.is_training_image, 00223 &p.training_label[0], 00224 &p.remote_command[0], 00225 (int) n, (int) nchunks_read); 00226 } 00227 00228 close(client_socket_fd); 00229 client_socket_fd = -1; 00230 00231 if (doquit) 00232 break; 00233 00234 pthread_mutex_lock(&q->m_patch_lock); 00235 nv2_image_patch_destroy(&q->m_patch); 00236 q->m_patch = p; 00237 pthread_mutex_unlock(&q->m_patch_lock); 00238 } 00239 00240 pthread_mutex_lock(&q->m_patch_lock); 00241 q->m_should_quit = 1; 00242 pthread_mutex_unlock(&q->m_patch_lock); 00243 00244 if (client_socket_fd >= 0) 00245 close(client_socket_fd); 00246 00247 close(q->socket_fd); 00248 00249 return (void*) 0; 00250 } 00251 00252 struct nv2_label_server* nv2_label_server_create( 00253 const int patch_reader_port, 00254 const char* remote_label_reader_addr, 00255 const int remote_label_reader_port) 00256 { 00257 struct nv2_label_server* p = 00258 (struct nv2_label_server*) 00259 malloc(sizeof(struct nv2_label_server)); 00260 00261 if (p == 0) 00262 nv2_fatal("malloc() failed"); 00263 00264 pthread_mutex_init(&p->m_patch_lock, 0); 00265 nv2_image_patch_init_empty(&p->m_patch); 00266 p->m_should_quit = 0; 00267 00268 p->m_patch_reader_port = patch_reader_port; 00269 00270 if (inet_aton(remote_label_reader_addr, 00271 &p->m_remote_label_reader_in_addr) == 0) 00272 nv2_fatal("inet_aton() failed"); 00273 00274 p->m_remote_label_reader_port = remote_label_reader_port; 00275 00276 p->socket_fd = -1; 00277 00278 p->m_verbosity = 2; 00279 00280 if (0 != pthread_create(&p->m_patch_reader_thread, 0, 00281 &run_patch_reader, 00282 (void*) p)) 00283 nv2_fatal("pthread_create() failed"); 00284 00285 return p; 00286 } 00287 00288 00289 void nv2_label_server_destroy(struct nv2_label_server* p) 00290 { 00291 if (p->socket_fd != -1) 00292 { 00293 const int oldfd = p->socket_fd; 00294 p->socket_fd = -1; 00295 close(oldfd); 00296 } 00297 00298 if (0 != pthread_join(p->m_patch_reader_thread, 0)) 00299 nv2_fatal("pthread_join() failed"); 00300 nv2_image_patch_destroy(&p->m_patch); 00301 pthread_mutex_destroy(&p->m_patch_lock); 00302 } 00303 00304 enum nv2_image_patch_result 00305 nv2_label_server_get_current_patch(struct nv2_label_server* p, 00306 struct nv2_image_patch* ret) 00307 { 00308 pthread_mutex_lock(&p->m_patch_lock); 00309 *ret = p->m_patch; 00310 const int doquit = p->m_should_quit; 00311 nv2_image_patch_init_empty(&p->m_patch); 00312 pthread_mutex_unlock(&p->m_patch_lock); 00313 00314 if (doquit) return NV2_IMAGE_PATCH_END; 00315 else if (ret->id > 0) return NV2_IMAGE_PATCH_VALID; 00316 else return NV2_IMAGE_PATCH_NONE; 00317 } 00318 00319 enum nv2_label_send_result 00320 nv2_label_server_send_label(struct nv2_label_server* p, 00321 const struct nv2_patch_label* l) 00322 { 00323 const int socket_fd = socket(PF_INET, SOCK_STREAM, 0); 00324 00325 if (socket_fd == -1) 00326 nv2_fatal("socket() failed"); 00327 00328 // Specify the server address and port 00329 struct sockaddr_in name; 00330 name.sin_family = AF_INET; 00331 name.sin_addr = p->m_remote_label_reader_in_addr; 00332 name.sin_port = htons(p->m_remote_label_reader_port); 00333 00334 struct nv2_patch_label nl = *l; 00335 nl.protocol_version = htonl(l->protocol_version); 00336 nl.patch_id = htonl(l->patch_id); 00337 nl.confidence = htonl(l->confidence); 00338 00339 enum nv2_label_send_result retval = NV2_LABEL_SEND_OK; 00340 00341 errno = 0; 00342 if (connect(socket_fd, (struct sockaddr*)(&name), sizeof(name)) 00343 == -1) 00344 { 00345 if (p->m_verbosity >= 1) 00346 nv2_warn("connect() failed"); 00347 retval = NV2_LABEL_SEND_FAIL; 00348 } 00349 else if (nv2_robust_write(socket_fd, &nl, sizeof(nl)) 00350 != sizeof(nl)) 00351 { 00352 if (p->m_verbosity >= 1) 00353 nv2_warn("write(nv2_patch_label) failed"); 00354 retval = NV2_LABEL_SEND_FAIL; 00355 } 00356 00357 close(socket_fd); 00358 00359 return retval; 00360 } 00361 00362 void nv2_label_server_set_verbosity(struct nv2_label_server* p, 00363 const int verbosity) 00364 { 00365 p->m_verbosity = verbosity; 00366 } 00367 00368 // ###################################################################### 00369 /* So things look consistent in everyone's emacs... */ 00370 /* Local Variables: */ 00371 /* indent-tabs-mode: nil */ 00372 /* c-file-style: "linux" */ 00373 /* End: */ 00374 00375 #endif // NEOVISIONII_NV2_LABEL_SERVER_C_DEFINED