/*---------------------------------------------------------------------- | ATX_HttpResponse_Emit +---------------------------------------------------------------------*/ extern ATX_Result ATX_HttpResponse_Emit(const ATX_HttpResponse* response, ATX_OutputStream* stream) { /* check that we have what we need */ if (ATX_String_IsEmpty(&response->base.protocol)) return ATX_ERROR_INVALID_PARAMETERS; if (response->status_code >= 1000) return ATX_ERROR_INVALID_PARAMETERS; /* output response line */ ATX_OutputStream_WriteString(stream, ATX_CSTR(response->base.protocol)); { char code_string[5]; unsigned code_int = response->status_code; code_string[0] = ' '; code_string[1] = '0' + code_int/100; code_int -= 100*(code_int/100); code_string[2] = '0' + code_int/10; code_int -= 10*(code_int/10); code_string[3] = '0' + code_int; code_string[4] = ' '; ATX_OutputStream_Write(stream, code_string, 5, NULL); } ATX_OutputStream_WriteString(stream, ATX_CSTR(response->reason_phrase)); ATX_OutputStream_Write(stream, "\r\n", 2, NULL); /* output the rest of the message */ return ATX_HttpMessage_Emit((ATX_HttpMessage*)response, stream); }
/*---------------------------------------------------------------------- | AlsaOutput_Open +---------------------------------------------------------------------*/ static BLT_Result AlsaOutput_Open(AlsaOutput* self) { int io_result; ATX_LOG_FINE_1("openning output - name=%s", ATX_CSTR(self->device_name)); switch (self->state) { case BLT_ALSA_OUTPUT_STATE_CLOSED: ATX_LOG_FINER("snd_pcm_open"); io_result = snd_pcm_open(&self->device_handle, ATX_CSTR(self->device_name), SND_PCM_STREAM_PLAYBACK, 0); if (io_result != 0) { self->device_handle = NULL; return BLT_FAILURE; } break; case BLT_ALSA_OUTPUT_STATE_OPEN: /* ignore */ return BLT_SUCCESS; case BLT_ALSA_OUTPUT_STATE_CONFIGURED: case BLT_ALSA_OUTPUT_STATE_PREPARED: return BLT_FAILURE; } /* update the state */ AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_OPEN); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_TcpNetworkStream_Create +---------------------------------------------------------------------*/ BLT_Result BLT_TcpNetworkStream_Create(const char* name, ATX_InputStream** stream) { ATX_Socket* sock; ATX_String hostname = ATX_String_Create(name); ATX_UInt16 port = BLT_TCP_NETWORK_STREAM_DEFAULT_PORT; int sep; ATX_Result result = ATX_SUCCESS; /* default */ *stream = NULL; /* parse the hostname/port */ sep = ATX_String_FindCharFrom(&hostname, ':', 6); if (sep > 0) { /* we have a port number */ int port_long = 0; result = ATX_ParseInteger(name+sep+1, &port_long, ATX_FALSE); if (ATX_FAILED(result)) { ATX_LOG_WARNING("BLT_TcpNetworkStream_Create - invalid port spec"); goto end; } port = (ATX_UInt16)port_long; ATX_String_SetLength(&hostname, sep); } /* create a socket */ result = ATX_TcpClientSocket_Create(&sock); if (ATX_FAILED(result)) goto end; /* connect */ ATX_LOG_FINE_2("BLT_TcpNetworkStream_Create - connecting to %s:%d", ATX_CSTR(hostname), port); result = ATX_Socket_ConnectToHost(sock, ATX_CSTR(hostname), port, BLT_TCP_NETWORK_STREAM_DEFAULT_TIMEOUT); if (ATX_FAILED(result)) { ATX_LOG_WARNING_1("BLT_TcpNetworkStream_Create - failed to connect (%d)", result); goto end; } ATX_LOG_FINE("BLT_TcpNetworkStream_Create - connected"); /* return the input stream */ result = ATX_Socket_GetInputStream(sock, stream); /* release the socket */ ATX_DESTROY_OBJECT(sock); end: ATX_String_Destruct(&hostname); return result; }
/*---------------------------------------------------------------------- | ATX_HttpMessage_Emit +---------------------------------------------------------------------*/ static ATX_Result ATX_HttpMessage_Emit(const ATX_HttpMessage* message, ATX_OutputStream* stream) { ATX_ListItem* item = ATX_List_GetFirstItem(message->headers); /* output the headers */ while (item) { ATX_HttpHeader* header = ATX_ListItem_GetData(item); if (header && !ATX_String_IsEmpty(&header->name) && !ATX_String_IsEmpty(&header->value)) { ATX_OutputStream_WriteString(stream, ATX_CSTR(header->name)); ATX_OutputStream_Write(stream, ": ", 2, NULL); ATX_OutputStream_WriteLine(stream, ATX_CSTR(header->value)); ATX_LOG_FINE_2("ATX_HttpMessage::Emit - %s: %s", ATX_CSTR(header->name), ATX_CSTR(header->value)); } item = ATX_ListItem_GetNext(item); } return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | ATX_HttpRequest_Emit +---------------------------------------------------------------------*/ ATX_Result ATX_HttpRequest_Emit(const ATX_HttpRequest* request, ATX_OutputStream* stream) { /* check that we have all we need */ if (ATX_String_IsEmpty(&request->method) || ATX_String_IsEmpty(&request->base.protocol)) { return ATX_ERROR_INVALID_PARAMETERS; } /* output the request line */ ATX_OutputStream_WriteString(stream, ATX_CSTR(request->method)); ATX_OutputStream_Write(stream, " ", 1, NULL); ATX_OutputStream_WriteString(stream, ATX_CSTR(request->url.path)); ATX_OutputStream_Write(stream, " ", 1, NULL); ATX_OutputStream_WriteString(stream, ATX_CSTR(request->base.protocol)); /* output the headers */ ATX_HttpMessage_Emit(&request->base, stream); /* terminating line */ ATX_OutputStream_Write(stream, "\r\n", 2, NULL); return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | Listener_OnPropertyChanged +---------------------------------------------------------------------*/ static void Listener_OnPropertyChanged(ATX_PropertyListener* _self, ATX_CString name, ATX_PropertyType type, const ATX_PropertyValue* value) { Listener* self = ATX_SELF(Listener, ATX_PropertyListener); ATX_Debug("OnPropertyChanged[%s]: ", ATX_CSTR(self->name)); if (value) { PrintProperty(name, type, value); } else { ATX_Debug("name=%s [REMOVED]\n", name); } }
/*---------------------------------------------------------------------- | ATX_HttpRequest_Create +---------------------------------------------------------------------*/ ATX_Result ATX_HttpRequest_Create(ATX_CString method, ATX_CString url, ATX_HttpRequest** request) { ATX_Result result; /* allocate a new object */ *request = (ATX_HttpRequest*)ATX_AllocateZeroMemory(sizeof(ATX_HttpRequest)); if (*request == NULL) { return ATX_ERROR_OUT_OF_MEMORY; } /* construct the base object */ result = ATX_HttpMessage_Construct(&(*request)->base); if (ATX_FAILED(result)) { ATX_FreeMemory((void*)request); return result; } /* construct the object */ (*request)->method = ATX_String_Create(method); result = ATX_HttpUrl_Construct(&(*request)->url, url); if (ATX_FAILED(result)) { ATX_HttpMessage_Destruct(&(*request)->base); ATX_FreeMemory((void*)request); return result; } /* set the host header */ if (!ATX_String_IsEmpty(&(*request)->url.host)) { ATX_HttpMessage_SetHeader((ATX_HttpMessage*)(*request), ATX_HTTP_HEADER_HOST, ATX_CSTR((*request)->url.host)); } return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | ATX_HttpResponse_Parse +---------------------------------------------------------------------*/ static ATX_Result ATX_HttpResponse_Parse(ATX_HttpResponse* response, ATX_InputStream* stream) { char buffer[ATX_HTTP_MAX_LINE_SIZE+1]; char* line = buffer; char* find; ATX_Boolean header_pending = ATX_FALSE; ATX_String header_name = ATX_EMPTY_STRING; ATX_String header_value = ATX_EMPTY_STRING; ATX_Result result; /* get the first line from the stream */ result = ATX_InputStream_ReadLine(stream, line, sizeof(buffer), NULL); if (ATX_FAILED(result)) return result; /* get the protocol */ find = (char*)ATX_Http_FindChar(line, ' '); if (find == NULL) { return ATX_ERROR_INVALID_SYNTAX; } *find = '\0'; ATX_String_Assign(&response->base.protocol, line); /* get the status code */ line = (char*)ATX_Http_SkipWhitespace(find+1); find = (char*)ATX_Http_FindChar(line, ' '); if (find == NULL) { return ATX_ERROR_INVALID_SYNTAX; } *find = '\0'; if (ATX_StringLength(line) != 3) { return ATX_ERROR_INVALID_SYNTAX; } { int i; response->status_code = 0; for (i=0; i<3; i++) { if (line[i] < '0' || line[i] > '9') { return ATX_ERROR_INVALID_SYNTAX; } response->status_code *= 10; response->status_code += line[i]-'0'; } } /* the rest is the reason phrase */ line = (char*)ATX_Http_SkipWhitespace(find+1); ATX_String_Assign(&response->reason_phrase, line); /* parse headers until an empty line or end of stream */ do { /* read a line */ result = ATX_InputStream_ReadLine(stream, line, sizeof(buffer), NULL); if (ATX_FAILED(result)) break; /* stop if line is empty */ if (line[0] == '\0' || line[0] == '\r' || line[0] == '\n') { if (header_pending) { ATX_String_TrimWhitespace(&header_value); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)response, ATX_CSTR(header_name), ATX_CSTR(header_value)); ATX_LOG_FINE_2("ATX_HttpResponse::Parse - %s: %s", ATX_CSTR(header_name), ATX_CSTR(header_value)); } break; } /* process the line */ if ((line[0] == ' ' || line[0] == '\t') && header_pending) { /* this is a line continuation */ ATX_String_Append(&header_value, line+1); } else { /* this is a new header */ const char* name; const char* value; /* add the pending header to the list */ if (header_pending) { ATX_String_TrimWhitespace(&header_value); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)response, ATX_CSTR(header_name), ATX_CSTR(header_value)); ATX_LOG_FINE_2("ATX_HttpResponse::Parse - %s: %s", ATX_CSTR(header_name), ATX_CSTR(header_value)); } /* parse header name */ name = ATX_Http_SkipWhitespace(line); value = ATX_Http_FindChar(name, ':'); ATX_String_AssignN(&header_name, name, (ATX_Size)(value-name)); value = ATX_Http_SkipWhitespace(value+1); ATX_String_Assign(&header_value, value); /* don't add the header now, it could be continued */ header_pending = ATX_TRUE; } } while(ATX_SUCCEEDED(result)); /* keep a reference to the stream */ response->base.body = stream; ATX_REFERENCE_OBJECT(stream); /* cleanup */ ATX_String_Destruct(&header_name); ATX_String_Destruct(&header_value); return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | ATX_HttpClient_SendRequestOnce +---------------------------------------------------------------------*/ static ATX_Result ATX_HttpClient_SendRequestOnce(ATX_HttpClient* self, ATX_HttpRequest* request, ATX_HttpResponse** response) { ATX_SocketAddress address; ATX_Socket* connection = NULL; ATX_InputStream* input_stream = NULL; ATX_OutputStream* output_stream = NULL; ATX_Result result; ATX_COMPILER_UNUSED(self); /* set default return value */ *response = NULL; /* resolve the host address */ ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - resolving name [%s]...", ATX_CSTR(request->url.host)); result = ATX_IpAddress_ResolveName(&address.ip_address, ATX_CSTR(request->url.host), ATX_HTTP_RESOLVER_TIMEOUT); if (ATX_FAILED(result)) return result; address.port = request->url.port; ATX_LOG_INFO("ATX_HttpClient::SendRequest - name resolved"); /* setup some headers */ ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_CONNECTION, "close"); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_HOST, ATX_CSTR(request->url.host)); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_USER_AGENT, ATX_HTTP_HEADER_DEFAULT_AGENT); /* create a socket to connect to the server */ result = ATX_TcpClientSocket_Create(&connection); if (ATX_FAILED(result)) return result; /* connect to the server */ ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - connecting on port %d...", request->url.port); result = ATX_Socket_Connect(connection, &address, ATX_HTTP_CONNECT_TIMEOUT); if (ATX_FAILED(result)) goto end; /* emit the request onto the connection */ result = ATX_Socket_GetOutputStream(connection, &output_stream); if (ATX_FAILED(result)) goto end; result = ATX_HttpRequest_Emit(request, output_stream); if (ATX_FAILED(result)) goto end; /* create a response from the connection's input stream */ result = ATX_Socket_GetInputStream(connection, &input_stream); if (ATX_FAILED(result)) goto end; result = ATX_HttpResponse_CreateFromStream(input_stream, response); if (ATX_FAILED(result)) { *response = NULL; goto end; } end: if (ATX_FAILED(result)) { if (*response != NULL) { ATX_HttpResponse_Destroy(*response); } } ATX_RELEASE_OBJECT(input_stream); ATX_RELEASE_OBJECT(output_stream); ATX_DESTROY_OBJECT(connection); return result; }
/*---------------------------------------------------------------------- | StdcFile_Open +---------------------------------------------------------------------*/ ATX_METHOD StdcFile_Open(ATX_File* _self, ATX_Flags mode) { StdcFile* self = ATX_SELF(StdcFile, ATX_File); FILE* stdc_file; /* decide wheter this is a file or stdin/stdout/stderr */ if (ATX_String_Equals(&self->name, ATX_FILE_STANDARD_INPUT, ATX_FALSE)) { stdc_file = stdin; } else if (ATX_String_Equals(&self->name, ATX_FILE_STANDARD_OUTPUT, ATX_FALSE)) { stdc_file = stdout; } else if (ATX_String_Equals(&self->name, ATX_FILE_STANDARD_ERROR, ATX_FALSE)) { stdc_file = stderr; } else { const char* fmode = ""; /* compute mode */ if (mode & ATX_FILE_OPEN_MODE_WRITE) { if (mode & ATX_FILE_OPEN_MODE_CREATE) { if (mode & ATX_FILE_OPEN_MODE_TRUNCATE) { /* write, read, create, truncate */ fmode = "w+b"; } else { /* write, read, create */ fmode = "a+b"; } } else { if (mode & ATX_FILE_OPEN_MODE_TRUNCATE) { /* write, read, truncate */ fmode = "w+b"; } else { /* write, read */ fmode = "r+b"; } } } else { /* read only */ fmode = "rb"; } /* try to open the file */ stdc_file = fopen(ATX_CSTR(self->name), fmode); if (stdc_file == NULL) { switch (errno) { case EACCES: return ATX_ERROR_ACCESS_DENIED; case ENOENT: return ATX_ERROR_NO_SUCH_FILE; default: return ATX_ERROR_ERRNO(errno); } } } /* set the buffered/unbuffered option */ if (mode & ATX_FILE_OPEN_MODE_UNBUFFERED) { setvbuf(stdc_file, NULL, _IONBF, 0); } /* remember the mode */ self->mode = mode; /* create a wrapper */ return StdcFileWrapper_Create(stdc_file, self->size, &self->file); }