void SocketService::run(void) { timeout_t timer, expires; SocketPort *port; unsigned char buf; #ifdef USE_POLL Poller mfd; pollfd * p_ufd; int lastcount = 0; // initialize ufd in all attached ports : // probably don't need this but it can't hurt. enterMutex(); port = first; while(port) { port->ufd = 0; port = port->next; } leaveMutex(); #else struct timeval timeout, *tvp; fd_set inp, out, err; FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); int so; #endif setCancel(cancelDeferred); for(;;) { timer = TIMEOUT_INF; while(1 == ::read(iosync[0], (char *)&buf, 1)) { if(buf) { onUpdate(buf); continue; } setCancel(cancelImmediate); sleep(TIMEOUT_INF); exit(); } #ifdef USE_POLL bool reallocate = false; MUTEX_START onEvent(); port = first; while(port) { onCallback(port); if ( ( p_ufd = port->ufd ) ) { if ( ( POLLHUP | POLLNVAL ) & p_ufd->revents ) { // Avoid infinite loop from disconnected sockets port->detect_disconnect = false; p_ufd->events &= ~POLLHUP; SocketPort* p = port; port = port->next; detach(p); reallocate = true; p->disconnect(); continue; } if ( ( POLLIN | POLLPRI ) & p_ufd->revents ) port->pending(); if ( POLLOUT & p_ufd->revents ) port->output(); } else { reallocate = true; } retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } // // reallocate things if we saw a ServerPort without // ufd set ! if ( reallocate || ( ( count + 1 ) != lastcount ) ) { lastcount = count + 1; p_ufd = mfd.getList( count + 1 ); // Set up iosync polling p_ufd->fd = iosync[0]; p_ufd->events = POLLIN | POLLHUP; p_ufd ++; port = first; while(port) { p_ufd->fd = port->so; p_ufd->events = ( port->detect_disconnect ? POLLHUP : 0 ) | ( port->detect_output ? POLLOUT : 0 ) | ( port->detect_pending ? POLLIN : 0 ) ; port->ufd = p_ufd; p_ufd ++; port = port->next; } } MUTEX_END poll( mfd.getList(), lastcount, timer ); #else MUTEX_START onEvent(); port = first; while(port) { onCallback(port); so = port->so; if(FD_ISSET(so, &err)) { port->detect_disconnect = false; SocketPort* p = port; port = port->next; p->disconnect(); continue; } if(FD_ISSET(so, &inp)) port->pending(); if(FD_ISSET(so, &out)) port->output(); retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; // if we expire, get new scheduling now if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); FD_SET(iosync[0],&inp); port = first; while(port) { so = port->so; if(port->detect_pending) FD_SET(so, &inp); if(port->detect_output) FD_SET(so, &out); if(port->detect_disconnect) FD_SET(so, &err); port = port->next; } MUTEX_END if(timer == TIMEOUT_INF) tvp = NULL; else { tvp = &timeout; timeout.tv_sec = timer / 1000; timeout.tv_usec = (timer % 1000) * 1000; } select(hiwater, &inp, &out, &err, tvp); #endif } }
static Port * OpenPortInternal(const DeviceConfig &config, DataHandler &handler) { const TCHAR *path = NULL; TCHAR buffer[MAX_PATH]; switch (config.port_type) { case DeviceConfig::PortType::DISABLED: return NULL; case DeviceConfig::PortType::SERIAL: if (config.path.empty()) return NULL; path = config.path.c_str(); break; case DeviceConfig::PortType::RFCOMM: #ifdef ANDROID if (config.bluetooth_mac.empty()) { LogStartUp(_T("No Bluetooth MAC configured")); return NULL; } return OpenAndroidBluetoothPort(config.bluetooth_mac, handler); #else LogStartUp(_T("Bluetooth not available on this platform")); return NULL; #endif case DeviceConfig::PortType::RFCOMM_SERVER: #ifdef ANDROID return OpenAndroidBluetoothServerPort(handler); #else LogStartUp(_T("Bluetooth not available on this platform")); return NULL; #endif case DeviceConfig::PortType::IOIOUART: #if defined(ANDROID) && defined(IOIOLIB) if (config.ioio_uart_id >= AndroidIOIOUartPort::getNumberUarts()) { LogStartUp(_T("No IOIOUart configured in profile")); return NULL; } return OpenAndroidIOIOUartPort(config.ioio_uart_id, config.baud_rate, handler); #else LogStartUp(_T("IOIO Uart not available on this platform or version")); return NULL; #endif case DeviceConfig::PortType::AUTO: if (!detect_gps(buffer, sizeof(buffer))) { LogStartUp(_T("no GPS detected")); return NULL; } LogStartUp(_T("GPS detected: %s"), buffer); path = buffer; break; case DeviceConfig::PortType::INTERNAL: break; case DeviceConfig::PortType::TCP_LISTENER: { TCPPort *port = new TCPPort(handler); if (!port->Open(config.tcp_port)) { delete port; return NULL; } return port; } case DeviceConfig::PortType::UDP_LISTENER: { SocketPort *port = new SocketPort(handler); if (!port->OpenUDPListener(config.tcp_port)) { delete port; return NULL; } return port; } case DeviceConfig::PortType::PTY: { #if defined(HAVE_POSIX) && !defined(ANDROID) if (config.path.empty()) return NULL; if (unlink(config.path.c_str()) < 0 && errno != ENOENT) return NULL; TTYPort *port = new TTYPort(handler); const char *slave_path = port->OpenPseudo(); if (slave_path == NULL) { delete port; return NULL; } if (symlink(slave_path, config.path.c_str()) < 0) { delete port; return NULL; } return port; #else return NULL; #endif } } if (path == NULL) return NULL; #ifdef HAVE_POSIX TTYPort *port = new TTYPort(handler); #else SerialPort *port = new SerialPort(handler); #endif if (!port->Open(path, config.baud_rate)) { delete port; return NULL; } return port; }
static Port * OpenPortInternal(const DeviceConfig &config, PortListener *listener, DataHandler &handler) { const TCHAR *path = nullptr; TCHAR buffer[MAX_PATH]; switch (config.port_type) { case DeviceConfig::PortType::DISABLED: return nullptr; case DeviceConfig::PortType::SERIAL: if (config.path.empty()) return nullptr; path = config.path.c_str(); break; case DeviceConfig::PortType::RFCOMM: #ifdef ANDROID if (config.bluetooth_mac.empty()) { LogFormat("No Bluetooth MAC configured"); return nullptr; } return OpenAndroidBluetoothPort(config.bluetooth_mac, listener, handler); #else LogFormat("Bluetooth not available on this platform"); return nullptr; #endif case DeviceConfig::PortType::RFCOMM_SERVER: #ifdef ANDROID return OpenAndroidBluetoothServerPort(listener, handler); #else LogFormat("Bluetooth not available on this platform"); return nullptr; #endif case DeviceConfig::PortType::IOIOUART: #if defined(ANDROID) if (config.ioio_uart_id >= AndroidIOIOUartPort::getNumberUarts()) { LogFormat("No IOIOUart configured in profile"); return nullptr; } return OpenAndroidIOIOUartPort(config.ioio_uart_id, config.baud_rate, listener, handler); #else LogFormat("IOIO Uart not available on this platform or version"); return nullptr; #endif case DeviceConfig::PortType::AUTO: if (!DetectGPS(buffer, sizeof(buffer))) { LogFormat("no GPS detected"); return nullptr; } LogFormat(_T("GPS detected: %s"), buffer); path = buffer; break; case DeviceConfig::PortType::INTERNAL: case DeviceConfig::PortType::DROIDSOAR_V2: case DeviceConfig::PortType::NUNCHUCK: case DeviceConfig::PortType::I2CPRESSURESENSOR: case DeviceConfig::PortType::IOIOVOLTAGE: break; case DeviceConfig::PortType::TCP_CLIENT: { const WideToUTF8Converter ip_address(config.ip_address); if (!ip_address.IsValid()) return nullptr; auto port = new TCPClientPort(listener, handler); if (!port->Connect(ip_address, config.tcp_port)) { delete port; return nullptr; } return port; } case DeviceConfig::PortType::TCP_LISTENER: { TCPPort *port = new TCPPort(listener, handler); if (!port->Open(config.tcp_port)) { delete port; return nullptr; } return port; } case DeviceConfig::PortType::UDP_LISTENER: { SocketPort *port = new SocketPort(listener, handler); if (!port->OpenUDPListener(config.tcp_port)) { delete port; return nullptr; } return port; } case DeviceConfig::PortType::PTY: { #if defined(HAVE_POSIX) && !defined(ANDROID) if (config.path.empty()) return nullptr; if (unlink(config.path.c_str()) < 0 && errno != ENOENT) return nullptr; TTYPort *port = new TTYPort(listener, handler); const char *slave_path = port->OpenPseudo(); if (slave_path == nullptr) { delete port; return nullptr; } if (symlink(slave_path, config.path.c_str()) < 0) { delete port; return nullptr; } return port; #else return nullptr; #endif } } if (path == nullptr) return nullptr; #ifdef HAVE_POSIX TTYPort *port = new TTYPort(listener, handler); #else SerialPort *port = new SerialPort(listener, handler); #endif if (!port->Open(path, config.baud_rate)) { delete port; return nullptr; } return port; }
void SocketService::run(void) { timeout_t timer, expires; SocketPort *port; unsigned char buf; #ifndef WIN32 #ifdef USE_POLL Poller mfd; pollfd * p_ufd; int lastcount = 0; // initialize ufd in all attached ports : // probably don't need this but it can't hurt. enterMutex(); port = first; while(port) { port->ufd = 0; port = port->next; } leaveMutex(); #else struct timeval timeout, *tvp; fd_set inp, out, err; FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); int so; #endif #else // WIN32 int numHandle = 0; HANDLE hv[MAXIMUM_WAIT_OBJECTS]; #endif #ifdef WIN32 // FIXME: needed ? ResetEvent(sync->GetSync()); #endif setCancel(cancelDeferred); for(;;) { timer = TIMEOUT_INF; #ifndef WIN32 while(1 == ::read(iosync[0], (char *)&buf, 1)) { #else for(;;) { int f = sync->getFlag(); if (f < 0) break; buf = f; #endif if(buf) { onUpdate(buf); continue; } setCancel(cancelImmediate); sleep(TIMEOUT_INF); exit(); } #ifndef WIN32 #ifdef USE_POLL bool reallocate = false; MUTEX_START onEvent(); port = first; while(port) { onCallback(port); if ( ( p_ufd = port->ufd ) ) { if ( ( POLLHUP | POLLNVAL ) & p_ufd->revents ) { // Avoid infinite loop from disconnected sockets port->detect_disconnect = false; p_ufd->events &= ~POLLHUP; SocketPort* p = port; port = port->next; detach(p); reallocate = true; p->disconnect(); continue; } if ( ( POLLIN | POLLPRI ) & p_ufd->revents ) port->pending(); if ( POLLOUT & p_ufd->revents ) port->output(); } else { reallocate = true; } retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } // // reallocate things if we saw a ServerPort without // ufd set ! if ( reallocate || ( ( count + 1 ) != lastcount ) ) { lastcount = count + 1; p_ufd = mfd.getList( count + 1 ); // Set up iosync polling p_ufd->fd = iosync[0]; p_ufd->events = POLLIN | POLLHUP; p_ufd ++; port = first; while(port) { p_ufd->fd = port->so; p_ufd->events = ( port->detect_disconnect ? POLLHUP : 0 ) | ( port->detect_output ? POLLOUT : 0 ) | ( port->detect_pending ? POLLIN : 0 ) ; port->ufd = p_ufd; p_ufd ++; port = port->next; } } MUTEX_END poll( mfd.getList(), lastcount, timer ); #else MUTEX_START onEvent(); port = first; while(port) { onCallback(port); so = port->so; if(FD_ISSET(so, &err)) { port->detect_disconnect = false; SocketPort* p = port; port = port->next; p->disconnect(); continue; } if(FD_ISSET(so, &inp)) port->pending(); if(FD_ISSET(so, &out)) port->output(); retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; // if we expire, get new scheduling now if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); FD_SET(iosync[0],&inp); port = first; while(port) { so = port->so; if(port->detect_pending) FD_SET(so, &inp); if(port->detect_output) FD_SET(so, &out); if(port->detect_disconnect) FD_SET(so, &err); port = port->next; } MUTEX_END if(timer == TIMEOUT_INF) tvp = NULL; else { tvp = &timeout; timeout.tv_sec = timer / 1000; timeout.tv_usec = (timer % 1000) * 1000; } select(hiwater, &inp, &out, &err, tvp); #endif #else // WIN32 MUTEX_START onEvent(); hv[0] = sync->GetSync(); numHandle = 1; port = first; while(port) { onCallback(port); long events = 0; if(port->detect_pending) events |= FD_READ; if(port->detect_output) events |= FD_WRITE; if(port->detect_disconnect) events |= FD_CLOSE; // !!! ignore some socket on overflow !!! if (events && numHandle < MAXIMUM_WAIT_OBJECTS) { WSAEventSelect(port->so,port->event,events); hv[numHandle++] = port->event; } retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; // if we expire, get new scheduling now if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } MUTEX_END // FIXME: handle thread cancellation correctly DWORD res = WaitForMultipleObjects(numHandle,hv,FALSE,timer); switch (res) { case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: break; default: // FIXME: handle failures (detach SocketPort) if (res >= WAIT_OBJECT_0+1 && res <= WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS) { int curr = res - (WAIT_OBJECT_0); WSANETWORKEVENTS events; // search port MUTEX_START port = first; while(port) { if (port->event == hv[curr]) break; port = port->next; } MUTEX_END // if port not found ignore if (!port || port->event != hv[curr]) break; WSAEnumNetworkEvents(port->so,port->event,&events); if(events.lNetworkEvents & FD_CLOSE) { port->detect_disconnect = false; port->disconnect(); continue; } if(events.lNetworkEvents & FD_READ) port->pending(); if(events.lNetworkEvents & FD_WRITE) port->output(); } } #endif } }