Exemplo n.º 1
0
static int unreal_networking_client(
		struct lws *Wsi,
		enum lws_callback_reasons Reason,
		void *User,
		void *In,
		size_t Len)
{
	struct lws_context *Context = lws_get_context(Wsi);
	FWebSocket* Socket = (FWebSocket*)lws_context_user(Context);
	switch (Reason)
	{
	case LWS_CALLBACK_CLIENT_ESTABLISHED:
		{
			Socket->ConnectedCallBack.Broadcast();
			lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
			check(Socket->Wsi == Wsi);
		}
		break;
	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
		{
			Socket->ErrorCallBack.Broadcast();
			return -1;
		}
		break;
	case LWS_CALLBACK_CLIENT_RECEIVE:
		{
			// push it on the socket.
			Socket->OnRawRecieve(In, (uint32)Len, !!lws_frame_is_binary(Wsi));
			check(Socket->Wsi == Wsi);
			lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
			break;
		}
	case LWS_CALLBACK_CLIENT_WRITEABLE:
		{
			check(Socket->Wsi == Wsi);
			Socket->OnRawWebSocketWritable(Wsi);
			lws_callback_on_writable(Wsi);
			lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
			break;
		}
	case LWS_CALLBACK_CLOSED:
		{
			Socket->ErrorCallBack.Broadcast();
			return -1;
		}
	}

	return 0;
}
Exemplo n.º 2
0
int bmx_libwebsockets_lws_frame_is_binary(struct libwebsocket * wsi) {
	return lws_frame_is_binary(wsi);
}
Exemplo n.º 3
0
    //--------------------------------------------------------------
    unsigned int Reactor::_notify(Connection* conn,
                                enum libwebsocket_callback_reasons const reason,
                                const char* const _message,
                                const unsigned int len){
        
        // this happens with events that don't use the connection
        // so not always a problem
        if (conn == NULL || conn->protocol == NULL || conn->ws == NULL ){
            if (conn == NULL){
                ofLog(OF_LOG_WARNING, "[ofxLibwebsockets] connection is null ");
            } else {
                ofLog(OF_LOG_WARNING, "[ofxLibwebsockets] protocol is null");
            }
            return 1;
        }

        if (closeAndFree){
          closeAndFree = false;
          return -1;
        }
        
        std::string message;
        Event args(*conn, message);
        
        switch (reason) {
            // connection was not successful
            case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
                ofLogError()<<"[ofxLibwebsockets] Connection error";
                
                for (int i=0; i<connections.size(); i++){
                    if ( connections[i] == conn ){
                        connections.erase( connections.begin() + i );
                        break;
                    }
                }
                ofNotifyEvent(conn->protocol->oncloseEvent, args);
                break;
                
            // last thing that happens before connection goes dark
            case LWS_CALLBACK_WSI_DESTROY:
            {
                bool bFound = false;
                for (int i=0; i<connections.size(); i++){
                    if ( connections[i] == conn ){
                        bFound = true; // valid connection
                        connections.erase( connections.begin() + i );
                        break;
                    }
                }
                
                if ( bFound ) ofNotifyEvent(conn->protocol->oncloseEvent, args);
            }
                break;
            
            case LWS_CALLBACK_ESTABLISHED:          // server connected with client
            case LWS_CALLBACK_CLIENT_ESTABLISHED:   // client connected with server
                connections.push_back( conn );
                ofNotifyEvent(conn->protocol->onopenEvent, args);
                break;
                
            case LWS_CALLBACK_CLOSED:
                // erase connection from vector
                for (int i=0; i<connections.size(); i++){
                    if ( connections[i] == conn ){
                        connections.erase( connections.begin() + i );
                        break;
                    }
                }
                
                ofNotifyEvent(conn->protocol->oncloseEvent, args);
                break;
                
            case LWS_CALLBACK_SERVER_WRITEABLE:
            case LWS_CALLBACK_CLIENT_WRITEABLE:
                // idle is good! means you can write again
                conn->setIdle();
                break;
                
            case LWS_CALLBACK_RECEIVE:              // server receive
            case LWS_CALLBACK_CLIENT_RECEIVE:       // client receive
            case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
                {
                    
                    bool bFinishedReceiving = false;
                    
                    // decide if this is part of a larger message or not
                    size_t bytesLeft = libwebsockets_remaining_packet_payload( conn->ws );
                    
                    if ( !bReceivingLargeMessage && (bytesLeft > 0 || !libwebsocket_is_final_fragment( conn->ws )) ){
                        bReceivingLargeMessage = true;
                    }
                    
                    // text or binary?
                    int isBinary = lws_frame_is_binary(conn->ws);
                    
                    if (isBinary == 1 ){
                        // set binary flag on event
                        args.isBinary = true;
                        
                        if ( bReceivingLargeMessage){
                            // need to allocate data...
                            if ( largeBinarySize == 0 ){
                                largeBinaryMessage.set( _message, len );
                                largeBinarySize = len;
                            } else {
                                largeBinarySize += len;
                                largeBinaryMessage.append(_message, len);
                            }
                            
                            if ( bytesLeft == 0 && libwebsocket_is_final_fragment( conn->ws )){
                                // copy into event
                                args.data.set(largeBinaryMessage.getData(), largeBinaryMessage.size());
                                
                                bFinishedReceiving      = true;
                                bReceivingLargeMessage  = false;
                                largeBinaryMessage.clear();
                                largeBinarySize = 0;
                            }
                        } else {
                            args.data.set(_message, len);
                            
                            bFinishedReceiving      = true;
                            bReceivingLargeMessage  = false;
                            largeBinaryMessage.clear();
                            largeBinarySize = 0;
                        }
                    } else {
                        if (_message != NULL && len > 0){
                            args.message = std::string(_message, len);
                        }
                        
                        if ( bReceivingLargeMessage){
                            largeMessage += args.message;
                            if ( bytesLeft == 0 && libwebsocket_is_final_fragment( conn->ws )){
                                args.message = largeMessage;
                                bFinishedReceiving      = true;
                                bReceivingLargeMessage  = false;
                                largeMessage = "";
                            }
                        }
                        
                        if (_message != NULL && len > 0 && (!bReceivingLargeMessage || bFinishedReceiving) ){
                            args.json = Json::Value( Json::nullValue );
                            
                            bool parsingSuccessful = ( bParseJSON ? reader.parse( args.message, args.json ) : false);
                            if ( !parsingSuccessful ){
                                // report to the user the failure and their locations in the document.
                                ofLog( OF_LOG_VERBOSE, "[ofxLibwebsockets] Failed to parse JSON\n"+ reader.getFormatedErrorMessages() );
                                args.json = Json::Value( Json::nullValue );
                            }
                        }
                    }
                    
                    // only notify if we have a complete message
                    if (!bReceivingLargeMessage || bFinishedReceiving){
                        ofNotifyEvent(conn->protocol->onmessageEvent, args);
                    }
                }
                break;
                
            default:
                ofLogVerbose() << "[ofxLibwebsockets] received unknown event "<< reason <<endl;
                break;
        }
        
        return 0;
    }
int WebSocket::onSocketCallback(struct libwebsocket_context *ctx,
                     struct libwebsocket *wsi,
                     enum libwebsocket_callback_reasons reason,
                     void *user, void *in, size_t len)
{
	//CCLOG("socket callback for %d reason", reason);
    CCAssert(_wsContext == NULL || ctx == _wsContext, "Invalid context.");
    CCAssert(_wsInstance == NULL || wsi == NULL || wsi == _wsInstance, "Invaild websocket instance.");

	switch (reason)
    {
        case LWS_CALLBACK_DEL_POLL_FD:
        case LWS_CALLBACK_PROTOCOL_DESTROY:
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
            {
                WsMessage* msg = NULL;
                if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR
                    || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == kStateConnecting)
                    || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == kStateConnecting)
                    )
                {
                    msg = new WsMessage();
                    msg->what = WS_MSG_TO_UITHREAD_ERROR;
                    _readyState = kStateClosing;
                }
                else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == kStateClosing)
                {
                    msg = new WsMessage();
                    msg->what = WS_MSG_TO_UITHREAD_CLOSE;
                }

                if (msg)
                {
                    _wsHelper->sendMessageToUIThread(msg);
                }
            }
            break;
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
            {
                WsMessage* msg = new WsMessage();
                msg->what = WS_MSG_TO_UITHREAD_OPEN;
                _readyState = kStateOpen;
                /*
                 * start the ball rolling,
                 * LWS_CALLBACK_CLIENT_WRITEABLE will come next service
                 */
                libwebsocket_callback_on_writable(ctx, wsi);
                _wsHelper->sendMessageToUIThread(msg);
            }
            break;
            
        case LWS_CALLBACK_CLIENT_WRITEABLE:
            {
                pthread_mutex_lock(&_wsHelper->_subThreadWsMessageQueueMutex);
                std::list<WsMessage*>::iterator iter = _wsHelper->_subThreadWsMessageQueue->begin();
                
                int bytesWrite = 0;
                for (; iter != _wsHelper->_subThreadWsMessageQueue->end(); ++iter) {

                    WsMessage* subThreadMsg = *iter;
                    
                    if ( WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what
                      || WS_MSG_TO_SUBTRHEAD_SENDING_BINARY == subThreadMsg->what)
                    {
                        Data* data = (Data*)subThreadMsg->obj;

                        unsigned char* buf = new unsigned char[LWS_SEND_BUFFER_PRE_PADDING
                                                               + data->len + LWS_SEND_BUFFER_POST_PADDING];
                        
                        memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, data->len);
                        memcpy((char*)&buf[LWS_SEND_BUFFER_PRE_PADDING], data->bytes, data->len);
                        
                        enum libwebsocket_write_protocol writeProtocol;
                        
                        if (WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what)
                        {
                            writeProtocol = LWS_WRITE_TEXT;
                        }
                        else
                        {
                            writeProtocol = LWS_WRITE_BINARY;
                        }
                        
                        bytesWrite = libwebsocket_write(wsi,  &buf[LWS_SEND_BUFFER_PRE_PADDING], data->len, writeProtocol);
                        
                        if (bytesWrite < 0) {
                            CCLOGERROR("%s", "libwebsocket_write error...");
                        }
                        if (bytesWrite < data->len) {
                            CCLOGERROR("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n");
                        }
                        
                        CC_SAFE_DELETE_ARRAY(data->bytes);
                        CC_SAFE_DELETE(data);
                        CC_SAFE_DELETE_ARRAY(buf);
                    }
                    
                    CC_SAFE_DELETE(subThreadMsg);
                }

                _wsHelper->_subThreadWsMessageQueue->clear();
                
                pthread_mutex_unlock(&_wsHelper->_subThreadWsMessageQueueMutex);
                
                /* get notified as soon as we can write again */
                
                libwebsocket_callback_on_writable(ctx, wsi);
            }
            break;
            
        case LWS_CALLBACK_CLOSED:
            {
                
                CCLOG("%s", "connection closing..");

                _wsHelper->quitSubThread();
                
                if (_readyState != kStateClosed)
                {
                    WsMessage* msg = new WsMessage();
                    _readyState = kStateClosed;
                    msg->what = WS_MSG_TO_UITHREAD_CLOSE;
                    _wsHelper->sendMessageToUIThread(msg);
                }
            }
            break;
            
        case LWS_CALLBACK_CLIENT_RECEIVE:
            {
                if (in && len > 0)
                {
                    WsMessage* msg = new WsMessage();
                    msg->what = WS_MSG_TO_UITHREAD_MESSAGE;
                    
                    char* bytes = NULL;
                    Data* data = new Data();
                    
                    if (lws_frame_is_binary(wsi))
                    {
                        
                        bytes = new char[len];
                        data->isBinary = true;
                    }
                    else
                    {
                        bytes = new char[len+1];
                        bytes[len] = '\0';
                        data->isBinary = false;
                    }

                    memcpy(bytes, in, len);
                    
                    data->bytes = bytes;
                    data->len = len;
                    msg->obj = (void*)data;
                    
                    _wsHelper->sendMessageToUIThread(msg);
                }
            }
            break;
        default:
            break;
        
	}
    
	return 0;
}
Exemplo n.º 5
0
int WebSocket::onSocketCallback(struct libwebsocket_context *ctx,
                     struct libwebsocket *wsi,
                     int reason,
                     void *user, void *in, ssize_t len)
{
	//CCLOG("socket callback for %d reason", reason);
    CCAssert(_wsContext == nullptr || ctx == _wsContext, "Invalid context.");
    CCAssert(_wsInstance == nullptr || wsi == nullptr || wsi == _wsInstance, "Invaild websocket instance.");

	switch (reason)
    {
        case LWS_CALLBACK_DEL_POLL_FD:
        case LWS_CALLBACK_PROTOCOL_DESTROY:
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
            {
                WsMessage* msg = nullptr;
                if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR
                    || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == State::kStateConnecting)
                    || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == State::kStateConnecting)
                    )
                {
                    msg = new WsMessage();
                    msg->what = WS_MSG_TO_UITHREAD_ERROR;
                    _readyState = State::kStateClosing;
                }
                else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == State::kStateClosing)
                {
                    msg = new WsMessage();
                    msg->what = WS_MSG_TO_UITHREAD_CLOSE;
                }

                if (msg)
                {
                    _wsHelper->sendMessageToUIThread(msg);
                }
            }
            break;
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
            {
                WsMessage* msg = new WsMessage();
                msg->what = WS_MSG_TO_UITHREAD_OPEN;
                _readyState = State::kStateOpen;
                
                /*
                 * start the ball rolling,
                 * LWS_CALLBACK_CLIENT_WRITEABLE will come next service
                 */
                libwebsocket_callback_on_writable(ctx, wsi);
                _wsHelper->sendMessageToUIThread(msg);
            }
            break;
            
        case LWS_CALLBACK_CLIENT_WRITEABLE:
            {

                std::lock_guard<std::mutex> lk(_wsHelper->_subThreadWsMessageQueueMutex);
                                               
                std::list<WsMessage*>::iterator iter = _wsHelper->_subThreadWsMessageQueue->begin();
                
                int bytesWrite = 0;
                for (; iter != _wsHelper->_subThreadWsMessageQueue->end();)
                {
                    WsMessage* subThreadMsg = *iter;
                    
                    if ( WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what
                      || WS_MSG_TO_SUBTRHEAD_SENDING_BINARY == subThreadMsg->what)
                    {
                        Data* data = (Data*)subThreadMsg->obj;

                        const size_t c_bufferSize = WS_WRITE_BUFFER_SIZE;

                        size_t remaining = data->len - data->issued;
                        size_t n = min(remaining, c_bufferSize );
                        CCLOG("[websocket:send] total: %d, sent: %d, remaining: %d, buffer size: %d", static_cast<int>(data->len), static_cast<int>(data->issued), static_cast<int>(remaining), static_cast<int>(n));

                        unsigned char* buf = new unsigned char[LWS_SEND_BUFFER_PRE_PADDING + n + LWS_SEND_BUFFER_POST_PADDING];

                        memcpy((char*)&buf[LWS_SEND_BUFFER_PRE_PADDING], data->bytes + data->issued, n);
                        
                        int writeProtocol;
                        
                        if (data->issued == 0) {
							if (WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what)
							{
								writeProtocol = LWS_WRITE_TEXT;
							}
							else
							{
								writeProtocol = LWS_WRITE_BINARY;
							}

							// If we have more than 1 fragment
							if (data->len > c_bufferSize)
								writeProtocol |= LWS_WRITE_NO_FIN;
                        } else {
                        	// we are in the middle of fragments
                        	writeProtocol = LWS_WRITE_CONTINUATION;
                        	// and if not in the last fragment
                        	if (remaining != n)
                        		writeProtocol |= LWS_WRITE_NO_FIN;
                        }

                        bytesWrite = libwebsocket_write(wsi,  &buf[LWS_SEND_BUFFER_PRE_PADDING], n, (libwebsocket_write_protocol)writeProtocol);
                        CCLOG("[websocket:send] bytesWrite => %d", bytesWrite);

                        // Buffer overrun?
                        if (bytesWrite < 0)
                        {
                            break;
                        }
                        // Do we have another fragments to send?
                        else if (remaining != n)
                        {
                            data->issued += n;
                            break;
                        }
                        // Safely done!
                        else
                        {
                            CC_SAFE_DELETE_ARRAY(data->bytes);
                            CC_SAFE_DELETE(data);
                            CC_SAFE_DELETE_ARRAY(buf);
                            _wsHelper->_subThreadWsMessageQueue->erase(iter++);
                            CC_SAFE_DELETE(subThreadMsg);
                        }
                    }
                }
                
                /* get notified as soon as we can write again */
                
                libwebsocket_callback_on_writable(ctx, wsi);
            }
            break;
            
        case LWS_CALLBACK_CLOSED:
            {
                
                CCLOG("%s", "connection closing..");

                _wsHelper->quitSubThread();
                
                if (_readyState != State::kStateClosed)
                {
                    WsMessage* msg = new WsMessage();
                    _readyState = State::kStateClosed;
                    msg->what = WS_MSG_TO_UITHREAD_CLOSE;
                    _wsHelper->sendMessageToUIThread(msg);
                }
            }
            break;
            
        case LWS_CALLBACK_CLIENT_RECEIVE:
            {
                if (in && len > 0)
                {
                    // Accumulate the data (increasing the buffer as we go)
                    if (_currentDataLen == 0)
                    {
                        _currentData = new char[len];
                        memcpy (_currentData, in, len);
                        _currentDataLen = len;
                    }
                    else
                    {
                        char *new_data = new char [_currentDataLen + len];
                        memcpy (new_data, _currentData, _currentDataLen);
                        memcpy (new_data + _currentDataLen, in, len);
                        CC_SAFE_DELETE_ARRAY(_currentData);
                        _currentData = new_data;
                        _currentDataLen = _currentDataLen + len;
                    }

                    _pendingFrameDataLen = libwebsockets_remaining_packet_payload (wsi);

                    if (_pendingFrameDataLen > 0)
                    {
                        //CCLOG("%ld bytes of pending data to receive, consider increasing the libwebsocket rx_buffer_size value.", _pendingFrameDataLen);
                    }
                    
                    // If no more data pending, send it to the client thread
                    if (_pendingFrameDataLen == 0)
                    {
						WsMessage* msg = new WsMessage();
						msg->what = WS_MSG_TO_UITHREAD_MESSAGE;

						char* bytes = nullptr;
						Data* data = new Data();

						if (lws_frame_is_binary(wsi))
						{

							bytes = new char[_currentDataLen];
							data->isBinary = true;
						}
						else
						{
							bytes = new char[_currentDataLen+1];
							bytes[_currentDataLen] = '\0';
							data->isBinary = false;
						}

						memcpy(bytes, _currentData, _currentDataLen);

						data->bytes = bytes;
						data->len = _currentDataLen;
						msg->obj = (void*)data;

						CC_SAFE_DELETE_ARRAY(_currentData);
						_currentData = nullptr;
						_currentDataLen = 0;

						_wsHelper->sendMessageToUIThread(msg);
                    }
                }
            }
            break;
        default:
            break;
        
	}
    
	return 0;
}