static int _openTcpClient( UThread* ut, struct sockaddr* addr, socklen_t addrlen ) { SOCKET fd; #ifdef __APPLE__ int yes = 1; #endif fd = socket( AF_INET, SOCK_STREAM, 0 ); if( INVALID(fd) ) { ur_error( ut, UR_ERR_ACCESS, "socket %s", SOCKET_ERR ); return -1; } #ifdef __APPLE__ if( setsockopt( fd, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(int) ) != 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "setsockopt %s", SOCKET_ERR ); return -1; } #endif if( connect( fd, addr, addrlen ) < 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "connect %s", SOCKET_ERR ); return -1; } return fd; }
static int printInfoLog( UThread* ut, GLuint obj, int prog ) { GLint infologLength; GLint charsWritten; char* infoLog; if( prog ) glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &infologLength ); else glGetShaderiv( obj, GL_INFO_LOG_LENGTH, &infologLength ); if( infologLength > 0 ) { infoLog = (char*) malloc( infologLength ); if( prog ) glGetProgramInfoLog( obj, infologLength, &charsWritten, infoLog ); else glGetShaderInfoLog( obj, infologLength, &charsWritten, infoLog ); //fprintf( stderr, "%s\n", infoLog ); ur_error( ut, UR_ERR_SCRIPT, infoLog ); free( infoLog ); } else { ur_error( ut, UR_ERR_SCRIPT, prog ? "glLinkProgram failed" : "glCompileShader failed" ); } return UR_THROW; }
/* \param ext If non-zero, then bind socket to ext->addr. */ static int _openUdpSocket( UThread* ut, SocketExt* ext, int nowait ) { SOCKET fd; fd = socket( AF_INET, SOCK_DGRAM, 0 ); if( INVALID(fd) ) { ur_error( ut, UR_ERR_ACCESS, "socket %s", SOCKET_ERR ); return -1; } if( nowait ) { #ifdef _WIN32 u_long flags = 1; ioctlsocket( fd, FIONBIO, &flags ); #else fcntl( fd, F_SETFL, fcntl( fd, F_GETFL, 0 ) | O_NONBLOCK ); #endif } if( ext ) { if( bind( fd, &ext->addr, ext->addrlen ) < 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "bind %s", SOCKET_ERR ); return -1; } } return fd; }
static const UBuffer* _execBuf( UThread* ut, const UCell* cell, int fd ) { static const char* name[3] = { "input", "output", "error" }; const UBuffer* buf; if( fd == 0 ) buf = ur_bufferSer(cell); else if( ! (buf = ur_bufferSerM(cell)) ) return 0; if( buf->type == UT_BINARY ) { return buf; } else if( buf->type == UT_STRING ) { if( ! ur_strIsUcs2(buf) ) return buf; ur_error( ut, UR_ERR_TYPE, "execute does not handle UCS2 strings" ); } else { ur_error( ut, UR_ERR_TYPE, "execute expected binary!/string! for %s", name[fd] ); } return 0; }
static int thread_open( UThread* ut, const UPortDevice* pdev, const UCell* from, int opt, UCell* res ) { UBuffer* port; ThreadExt* ext; (void) from; (void) opt; ext = (ThreadExt*) memAlloc( sizeof(ThreadExt) ); if( ! ext ) return ur_error( ut, UR_ERR_INTERNAL, "Could not alloc thread port" ); if( ! _initThreadQueue( &ext->A ) ) { fail: memFree( ext ); return ur_error( ut, UR_ERR_INTERNAL, "Could not create thread queue" ); } if( ! _initThreadQueue( &ext->B ) ) { mutexFree( ext->A.mutex ); goto fail; } ext->A.END_OPEN = 0; ext->B.END_OPEN = 1; port = boron_makePort( ut, pdev, ext, res ); port->SIDE = SIDE_A; return UR_OK; }
/* "tcp://host:port" "tcp://:port" "udp://host:port" "udp://:port" */ static int socket_open( UThread* ut, const UPortDevice* pdev, const UCell* from, int opt, UCell* res ) { NodeServ ns; SocketExt* ext; int socket; int nowait = opt & UR_PORT_NOWAIT; //int port = 0; //int hostPort = 0; //UCell* initAddr = 0; if( ! ur_is(from, UT_STRING) ) return ur_error( ut, UR_ERR_TYPE, "socket open expected string" ); ext = (SocketExt*) memAlloc( sizeof(SocketExt) ); ext->addrlen = 0; #ifdef _WIN32 ext->event = WSA_INVALID_EVENT; #endif //if( ur_is(from, UT_STRING) ) { stringToNodeServ( ut, from, &ns ); if( ! makeSockAddr( ut, ext, &ns ) ) goto fail; } #if 0 else if( ur_is(from, UT_BLOCK) )
static int thread_seek( UThread* ut, UBuffer* port, UCell* pos, int where ) { (void) port; (void) pos; (void) where; return ur_error( ut, UR_ERR_SCRIPT, "Cannot seek on thread port" ); }
static int makeSockAddr( UThread* ut, SocketExt* ext, const NodeServ* ns ) { struct addrinfo hints; struct addrinfo* res; int err; memset( &hints, 0, sizeof(hints) ); hints.ai_family = AF_INET; // AF_UNSPEC hints.ai_socktype = ns->socktype; if( ! ns->node ) hints.ai_flags = AI_PASSIVE; err = getaddrinfo( ns->node, ns->service, &hints, &res ); if( err ) { return ur_error( ut, UR_ERR_SCRIPT, "getaddrinfo (%s)", gai_strerror( err ) ); } memcpy( &ext->addr, res->ai_addr, res->ai_addrlen ); ext->addrlen = res->ai_addrlen; freeaddrinfo( res ); return UR_OK; }
static int _execSpawn( UThread* ut, char* cmd, UCell* res ) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); // Start the child process. if( ! CreateProcess( NULL, // No module name (use command line). TEXT(cmd), // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. FALSE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ) // Pointer to PROCESS_INFORMATION structure. ) { return ur_error( ut, UR_ERR_INTERNAL, "CreateProcess failed (%d).\n", GetLastError() ); } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); ur_setId(res, UT_INT); ur_int(res) = pi.dwProcessId; return UR_OK; }
/* line-edit word!/string! <max-chars> */ static GWidget* ledit_make( UThread* ut, UBlockIter* bi, const GWidgetClass* wclass ) { LineEdit* ep; const UCell* arg[2]; int maxChars = 32; if( ! gui_parseArgs( ut, bi, wclass, ledit_args, arg ) ) return 0; if( ur_isShared( arg[0]->series.buf ) ) { ur_error( ut, UR_ERR_SCRIPT, "line-edit cannot modify shared string" ); return 0; } if( arg[1] ) maxChars = ur_int(arg[1]); ep = (LineEdit*) gui_allocWidget( sizeof(LineEdit), wclass ); ep->wid.flags |= CHANGED; //ep->state = LEDIT_STATE_DISPLAY; ep->strN = arg[0]->series.buf; ep->maxChars = maxChars; ep->vboN = ledit_vbo( ut, maxChars ); return (GWidget*) ep; }
static int ssl_write( UThread* ut, UBuffer* port, const UCell* data ) { const void* buf; SSLExt* ext = ur_ptr(SSLExt, port); int len; int n; len = boron_sliceMem( ut, data, &buf ); if( port->FD > -1 && len ) { retry: n = mbedtls_ssl_write( &ext->sc, buf, len ); if( n < 0 ) { if( n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE ) { ssl_wait(); goto retry; } // An error occured; the ssl context must not be used again. ssl_free( ext ); port->FD = -1; return ur_error( ut, UR_ERR_ACCESS, "ssl_write %d", n ); } else if( n != len ) { if( n > 0 && n < len ) { buf = ((const char*) buf) + n; len -= n; goto retry; } return ur_error( ut, UR_ERR_ACCESS, "ssl_write only sent %d of %d bytes", n, len ); } } return UR_OK; }
static int thread_read( UThread* ut, UBuffer* port, UCell* dest, int part ) { UBuffer tbuf; ThreadExt* ext = (ThreadExt*) port->ptr.v; ThreadQueue* queue; (void) part; tbuf.type = 0; queue = (port->SIDE == SIDE_A) ? &ext->B : &ext->A; if( ! queue->readIt ) readEvent( queue ); // Waits until data is available. mutexLock( queue->mutex ); while( queue->readIt >= queue->buf.used ) { if( condWaitF( queue->cond, queue->mutex ) ) { mutexUnlock( queue->mutex ); goto waitError; } } queue->readIt = thread_dequeue( &queue->buf, queue->readIt, dest, &tbuf ); mutexUnlock( queue->mutex ); if( tbuf.type ) { UIndex bufN; dest->series.buf = UR_INVALID_BUF; ur_genBuffers( ut, 1, &bufN ); dest->series.buf = bufN; memCpy( ur_buffer( bufN ), &tbuf, sizeof(UBuffer) ); } else { int type = ur_type(dest); if( ur_isWordType(type) ) { if( ur_binding(dest) == UR_BIND_THREAD ) ur_unbind(dest); } } return UR_OK; waitError: return ur_error( ut, UR_ERR_INTERNAL, "thread_read condWait failed" ); }
static SocketExt* _socketPort( UThread* ut, UCell* cell, const char* funcName ) { SocketExt* ext; UBuffer* pbuf = ur_buffer( cell->series.buf ); if( (pbuf->form == UR_PORT_EXT) && pbuf->ptr.v ) { ext = ur_ptr(SocketExt, pbuf); if( ext->dev == &port_socket ) return ext; } ur_error( ut, UR_ERR_SCRIPT, "%s expected socket port", funcName ); return 0; }
/* Return UR_OK/UR_THROW. */ int ur_makeDir( UThread* ut, const char* path ) { if( ! CreateDirectory( path, NULL ) ) { DWORD err; err = GetLastError(); if( (err != ERROR_FILE_EXISTS) || (_isDir(path) != 1) ) { ur_error( ut, UR_ERR_ACCESS, "CreateDirectory error (%d)", err ); return UR_THROW; } } return UR_OK; }
static int thread_write( UThread* ut, UBuffer* port, const UCell* data ) { UBuffer* buf; ThreadExt* ext = (ThreadExt*) port->ptr.v; ThreadQueue* queue; int type = ur_type(data); if( ur_isSeriesType(type) && ! ur_isShared( data->series.buf ) ) { buf = ur_bufferSerM( data ); if( ! buf ) return UR_THROW; if( ur_isBlockType(type) ) { UCell* it = buf->ptr.cell; UCell* end = it + buf->used; while( it != end ) { type = ur_type(it); if( ur_isWordType(type) ) { if( ur_binding(it) == UR_BIND_THREAD ) ur_unbind(it); } else if( ur_isSeriesType(type) ) { return ur_error( ut, UR_ERR_INTERNAL, "Cannot write block containing series to thread port" ); } ++it; } } } else buf = 0; queue = (port->SIDE == SIDE_A) ? &ext->A : &ext->B; mutexLock( queue->mutex ); if( queue->END_OPEN ) { thread_queue( &queue->buf, data, buf ); condSignal( queue->cond ); writeEvent( queue ); } mutexUnlock( queue->mutex ); return UR_OK; }
static int _openTcpServer( UThread* ut, struct sockaddr* addr, socklen_t addrlen, int backlog ) { SOCKET fd; int yes = 1; fd = socket( AF_INET, SOCK_STREAM, 0 ); if( INVALID(fd) ) { ur_error( ut, UR_ERR_ACCESS, "socket %s", SOCKET_ERR ); return -1; } if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int) ) != 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "setsockopt %s", SOCKET_ERR ); return -1; } if( bind( fd, addr, addrlen ) != 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "bind %s", SOCKET_ERR ); return -1; } if( listen( fd, backlog ) != 0 ) { closesocket( fd ); ur_error( ut, UR_ERR_ACCESS, "listen %s", SOCKET_ERR ); return -1; } return fd; }
static int ssl_read( UThread* ut, UBuffer* port, UCell* dest, int len ) { SSLExt* ext = ur_ptr(SSLExt, port); UBuffer* buf = ur_buffer( dest->series.buf ); int n; if( port->FD > -1 && len ) { retry: n = mbedtls_ssl_read( &ext->sc, buf->ptr.b + buf->used, len ); //printf( "KR ssl_read %d\n", n ); if( n > 0 ) { buf->used += n; } else if( n < 0 ) { if( n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE ) { ssl_wait(); goto retry; } // An error occured; the ssl context must not be used again. ssl_free( ext ); port->FD = -1; return ur_error( ut, UR_ERR_ACCESS, "ssl_read %d", n ); } else { ur_setId(dest, UT_NONE); } } return UR_OK; }
static GWidget* itemview_make( UThread* ut, UBlockIter* bi, const GWidgetClass* wclass ) { GItemView* ep; UIndex itemBlkN; const UCell* arg[3]; //int ok; if( ! gui_parseArgs( ut, bi, wclass, itemview_args, arg ) ) return 0; ep = (GItemView*) gui_allocWidget( sizeof(GItemView), wclass ); assert( sizeof(GLint) == sizeof(GLsizei) ); ur_arrInit( ep->fc + 0, sizeof(GLint), 0 ); ur_arrInit( ep->fc + 1, sizeof(GLint), 0 ); glGenBuffers( 2, ep->vbo ); ep->vboSize[0] = ep->vboSize[1] = 0; ep->use_color = -1; ep->selCol = -1; ep->selRow = -1; ep->itemCount = 0; ep->itemWidth = 0; ep->itemHeight = 0; ep->scrollY = 0; ep->modVbo = 0; ep->updateMethod = IV_UPDATE_2; ep->layoutBlkN = UR_INVALID_BUF; ep->selectBgBlkN = UR_INVALID_BUF; ep->bindCtxN = UR_INVALID_BUF; ep->actionBlkN = UR_INVALID_BUF; itemBlkN = arg[0]->series.buf; if( ur_isShared( itemBlkN ) ) ep->dataBlkN = UR_INVALID_BUF; else ep->dataBlkN = itemBlkN; // Optional action block. if( arg[2] ) ep->actionBlkN = arg[2]->series.buf; //-------------------------------------------- // Parse layout block [size coord! item block! selected block!] { UBlockIterM bi; UBuffer* ctx; if( ur_blkSliceM( ut, &bi, arg[1] ) != UR_OK ) goto fail; if( (bi.end - bi.it) < 3 ) goto bad_layout; ctx = gui_styleContext( ut ); if( ctx ) ur_bind( ut, bi.buf, ctx, UR_BIND_THREAD ); if( ur_is(bi.it, UT_COORD) ) { // Fixed layout. static char itemStr[] = "item"; UBuffer* blk; if( ! ur_is(bi.it + 1, UT_BLOCK) || ! ur_is(bi.it + 2, UT_BLOCK) ) goto bad_layout; ep->itemWidth = bi.it->coord.n[0]; ep->itemHeight = bi.it->coord.n[1]; //printf( "KR item dim %d,%d\n", ep->itemWidth, ep->itemHeight ); ++bi.it; ep->layoutBlkN = bi.it->series.buf; ep->bindCtxN = ur_makeContext( ut, 1 ); // gc! ctx = ur_buffer( ep->bindCtxN ); ur_ctxAppendWord( ctx, ur_intern( ut, itemStr, 4 ) ); if( ! (blk = ur_bufferSerM( bi.it )) ) goto fail; ur_bind( ut, blk, ctx, UR_BIND_THREAD ); ++bi.it; ep->selectBgBlkN = bi.it->series.buf; } #ifdef ITEMVIEW_BOX_LAYOUT else { // Automatic layout. glEnv.guiParsingItemView = 1; ok = gui_makeWidgets( ut, arg[1], &ep->wid, 0 ); glEnv.guiParsingItemView = 0; if( ! ok ) goto fail; //ep->wid.child->flags |= GW_HIDDEN; } #endif } return (GWidget*) ep; bad_layout: ur_error( ut, UR_ERR_SCRIPT, "Invalid item-view layout" ); fail: itemview_free( (GWidget*) ep ); return 0; }
/* Updates DrawContext attr & drawCount. Return UR_OK/UR_THROW. */ int itemview_parse( DrawContext* dc, UThread* ut, UBlockIter* bi, GWidget* wp ) { const UCell* arg[3]; UAtom atom; int opcode; float x, y; while( bi->it != bi->end ) { if( ur_is(bi->it, UT_WORD) ) { atom = ur_atom( bi->it ); opcode = ur_atomsSearch( glEnv.drawOpTable, DOP_COUNT, atom ); switch( opcode ) { case DOP_IMAGE: { QuadDim qd; int16_t rect[4]; const int16_t* coord; FETCH_ARGS( iv_args_image ); //printf( "KR IV image\n" ); coord = arg[0]->coord.n; rect[0] = coord[0] + dc->penX; rect[1] = coord[1] + dc->penY; rect[2] = coord[2]; rect[3] = coord[3]; quad_init( &qd, rect, arg[1]->coord.n, arg[2]->coord.n ); quad_emitVT( &qd, dc->attr, dc->attr + 3, AttrCount ); vbo_setVec3( dc->attr + 5, AttrCount, 6, dc->color ); dc->attr += 6 * AttrCount; dc->drawCount += 6; } break; case DOP_COLOR: FETCH_ARGS( iv_args_color ); dc->color[0] = (GLfloat) ur_int( arg[0] ); break; case DOP_FONT: FETCH_ARGS( iv_args_font ); dc->fontN = ur_fontTF( arg[0] ); break; case DOP_TEXT: FETCH_ARGS( iv_args_text ); x = dc->penX + (float) arg[0]->coord.n[0]; y = dc->penY + (float) arg[0]->coord.n[1]; { DrawTextState dts; UBinaryIter si; int glyphCount; //printf( "KR IV text\n" ); dp_toString( ut, arg[1], &si ); vbo_drawTextInit( &dts, (TexFont*) ur_buffer( dc->fontN )->ptr.v, x, y ); dts.emitTris = 1; glyphCount = vbo_drawText( &dts, dc->attr + 3, dc->attr, AttrCount, si.it, si.end ); glyphCount *= 6; vbo_setVec3( dc->attr + 5, AttrCount, glyphCount, dc->color ); /* while( si.it != si.end ) putchar( *si.it++ ); putchar( '\n' ); */ dc->attr += glyphCount * AttrCount; dc->drawCount += glyphCount; } break; default: goto invalid_op; } } else { goto invalid_op; } } return UR_OK; invalid_op: return ur_error( ut, UR_ERR_SCRIPT, "Invalid item-view instruction" ); }
/* Returns zero if matching rule not found or exception occured. */ static const UCell* _parseBin( UThread* ut, BinaryParser* pe, const UCell* rit, const UCell* rend, UIndex* spos ) { const UCell* set = 0; const UCell* tval; uint32_t bitCount; uint32_t field; UBuffer* ibin = ur_buffer( pe->inputBufN ); uint8_t* in = ibin->ptr.b + *spos; uint8_t* inEnd = ibin->ptr.b + pe->inputEnd; match: while( rit != rend ) { switch( ur_type(rit) ) { case UT_INT: bitCount = ur_int(rit); if( bitCount < 1 || bitCount > 32 ) { ur_error( PARSE_ERR, "bit-field size must be 1 to 32" ); goto parse_err; } if( bitCount > 24 ) { uint32_t high; in = pullBits( pe, bitCount - 16, in, inEnd, &high ); if( ! in ) goto failed; in = pullBits( pe, 16, in, inEnd, &field ); if( ! in ) goto failed; field |= high << 16; } else { in = pullBits( pe, bitCount, in, inEnd, &field ); if( ! in ) goto failed; } goto set_field; case UT_WORD: switch( ur_atom(rit) ) { case UR_ATOM_U8: if( in == inEnd ) goto failed; field = *in++; goto set_field; case UR_ATOM_U16: if( (inEnd - in) < 2 ) goto failed; if( pe->bigEndian ) field = (in[0] << 8) | in[1]; else field = (in[1] << 8) | in[0]; in += 2; goto set_field; case UR_ATOM_U32: if( (inEnd - in) < 4 ) goto failed; if( pe->bigEndian ) field = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; else field = (in[3] << 24) | (in[2] << 16) | (in[1] << 8) | in[0]; in += 4; goto set_field; case UR_ATOM_SKIP: ++rit; ++in; break; #if 0 case UR_ATOM_MARK: break; case UR_ATOM_PLACE: ++rit; if( (rit != rend) && ur_is(rit, UT_WORD) ) { tval = ur_wordCell( ut, rit++ ); CHECK_WORD(tval); if( ur_is(tval, UT_BINARY) ) { pos = tval->series.it; break; } } ur_error( PARSE_ERR, "place expected series word" ); goto parse_err; #endif case UR_ATOM_COPY: // copy dest size // word! int!/word! ++rit; if( (rit != rend) && ur_is(rit, UT_WORD) ) { UCell* res = ur_wordCellM( ut, rit ); CHECK_WORD(res); if( ++rit != rend ) { tval = rit++; if( ur_is(tval, UT_WORD) ) { tval = ur_wordCell( ut, tval ); CHECK_WORD(tval); } if( ur_is(tval, UT_INT) ) { UBuffer* cb; int size = ur_int(tval); cb = ur_makeBinaryCell( ut, size, res ); cb->used = size; memCpy( cb->ptr.b, in, size ); in += size; break; } } ur_error( PARSE_ERR, "copy expected int! count" ); goto parse_err; } ur_error( PARSE_ERR, "copy expected word! destination" ); goto parse_err; case UR_ATOM_BIG_ENDIAN: ++rit; pe->bigEndian = 1; break; case UR_ATOM_LITTLE_ENDIAN: ++rit; pe->bigEndian = 0; break; default: tval = ur_wordCell( ut, rit ); CHECK_WORD(tval); if( ur_is(tval, UT_CHAR) ) goto match_char; else if( ur_is(tval, UT_STRING) ) goto match_string; else if( ur_is(tval, UT_BLOCK) ) goto match_block; /* else if( ur_is(tval, UT_BITSET) ) goto match_bitset; */ else { ur_error( PARSE_ERR, "parse expected char!/string!/block!" ); goto parse_err; } break; } break; case UT_SETWORD: set = rit++; while( (rit != rend) && ur_is(rit, UT_SETWORD) ) ++rit; break; #if 0 case UT_GETWORD: break; case UT_INT: repMin = ur_int(rit); ++rit; if( rit == rend ) return 0; if( ur_is(rit, UT_INT) ) { repMax = ur_int(rit); ++rit; } else { repMax = repMin; } goto repeat; #endif case UT_CHAR: match_char: if( *in != ur_int(rit) ) goto failed; ++in; ++rit; break; case UT_BLOCK: tval = rit; match_block: { UBlockIter bi; UIndex pos = in - ibin->ptr.b; UIndex rblkN = tval->series.buf; ur_blkSlice( ut, &bi, tval ); tval = _parseBin( ut, pe, bi.it, bi.end, &pos ); ibin = ur_buffer( pe->inputBufN ); if( ! tval ) { if( pe->exception == PARSE_EX_ERROR ) { ur_appendTrace( ut, rblkN, 0 ); return 0; } if( pe->exception == PARSE_EX_BREAK ) pe->exception = PARSE_EX_NONE; else goto failed; } in = ibin->ptr.b + pos; inEnd = ibin->ptr.b + pe->inputEnd; ++rit; } break; case UT_PAREN: { UIndex pos = in - ibin->ptr.b; if( UR_OK != pe->eval( ut, rit ) ) goto parse_err; /* Re-acquire pointer & check if input modified. */ ibin = ur_buffer( pe->inputBufN ); if( pe->sliced ) { // We have no way to track changes to the end of a slice, // so just make sure we remain in valid memery. if( ibin->used < pe->inputEnd ) pe->inputEnd = ibin->used; } else { // Not sliced, track input end. if( ibin->used != pe->inputEnd ) pe->inputEnd = ibin->used; } in = ibin->ptr.b + pos; inEnd = ibin->ptr.b + pe->inputEnd; ++rit; } break; case UT_STRING: tval = rit; match_string: { UBinaryIter bi; int size; ur_binSlice( ut, &bi, tval ); if( ur_strIsUcs2(bi.buf) ) goto bad_enc; size = bi.end - bi.it; if( size > (inEnd - in) ) goto failed; if( match_pattern_8(in, inEnd, bi.it, bi.end) == bi.end ) { in += size; ++rit; } else goto failed; } break; #if 0 case UT_BITSET: tval = rit; match_bitset: if( pos >= pe->inputEnd ) goto failed; { const UBuffer* bin = ur_bufferSer( tval ); int c = istr->ptr.c[ pos ]; if( bitIsSet( bin->ptr.b, c ) ) { ++rit; ++pos; } else goto failed; } break; #endif default: ur_error( PARSE_ERR, "invalid parse value" ); //orDatatypeName( ur_type(rit) ) ); goto parse_err; } } //complete: *spos = in - ibin->ptr.b; return rit; set_field: if( set ) { UCell* val; while( set != rit ) { val = ur_wordCellM( ut, set++ ); CHECK_WORD(val); ur_setId(val, UT_INT); ur_int(val) = field; } set = 0; } ++rit; goto match; failed: *spos = in - ibin->ptr.b; return 0; bad_enc: ur_error( ut, UR_ERR_INTERNAL, "parse binary does not handle UCS2 strings" ); //goto parse_err; parse_err: pe->exception = PARSE_EX_ERROR; return 0; }
/* "tcps://host:port" "tcps://:port" "udps://host:port" "udps://:port" */ static int ssl_open( UThread* ut, const UPortDevice* pdev, const UCell* from, int opt, UCell* res ) { NodeServ ns; SSLExt* ext; int ok; //int nowait = opt & UR_PORT_NOWAIT; mbedtls_net_context* nc; mbedtls_ssl_context* sc; mbedtls_ssl_config* conf; const char* pers = "ssl_client1"; (void) opt; if( ! ur_is(from, UT_STRING) ) return ur_error( ut, UR_ERR_TYPE, "socket open expected string" ); ext = (SSLExt*) memAlloc( sizeof(SSLExt) ); ext->se.addrlen = 0; #ifdef _WIN32 ext->se.event = WSA_INVALID_EVENT; #endif //if( ur_is(from, UT_STRING) ) { stringToNodeServ( ut, from, &ns ); if( ! makeSockAddr( ut, &ext->se, &ns ) ) goto fail; } if( ! ns.service ) { ur_error( ut, UR_ERR_SCRIPT, "Socket port requires hostname and/or port" ); goto fail; } if( ! boron_requestAccess( ut, "Open socket %s", ns.service ) ) goto fail; ssl_init( ext ); nc = &ext->nc; sc = &ext->sc; conf = &ext->conf; ok = mbedtls_ctr_drbg_seed( &ext->ctr_drbg, mbedtls_entropy_func, &ext->entropy, (const unsigned char*) pers, strlen(pers) ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ctr_drbg_seed", ok ); goto failSSL; } ok = mbedtls_net_connect( nc, ns.node, ns.service, (ns.socktype == SOCK_DGRAM) ? MBEDTLS_NET_PROTO_UDP : MBEDTLS_NET_PROTO_TCP ); if( ok != 0 ) { ssl_error( ut, "mbedtls_net_connect", ok ); goto failSSL; } ok = mbedtls_ssl_config_defaults( conf, MBEDTLS_SSL_IS_CLIENT, (ns.socktype == SOCK_DGRAM) ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_config_defaults", ok ); goto failSSL; } mbedtls_ssl_conf_authmode( conf, MBEDTLS_SSL_VERIFY_NONE ); //mbedtls_ssl_conf_ca_chain( conf, cacert, NULL ); mbedtls_ssl_conf_rng( conf, mbedtls_ctr_drbg_random, &ext->ctr_drbg ); mbedtls_ssl_conf_dbg( conf, ssl_debug, stdout ); ok = mbedtls_ssl_setup( sc, conf ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_setup", ok ); goto failSSL; } ok = mbedtls_ssl_set_hostname( sc, "Boron TLS Server 1" ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_set_hostname", ok ); goto failSSL; } mbedtls_ssl_set_bio( sc, nc, mbedtls_net_send, mbedtls_net_recv, NULL ); while( (ok = mbedtls_ssl_handshake( sc )) != 0 ) { if( ok != MBEDTLS_ERR_SSL_WANT_READ && ok != MBEDTLS_ERR_SSL_WANT_WRITE ) { ssl_error( ut, "mbedtls_ssl_handshake", ok ); goto failSSL; } } { UBuffer* pbuf; pbuf = boron_makePort( ut, pdev, ext, res ); pbuf->TCP = (ns.socktype == SOCK_STREAM) ? 1 : 0; pbuf->FD = nc->fd; //printf( "KR socket_open %d %d\n", pbuf->FD, pbuf->TCP ); } return UR_OK; failSSL: ssl_free( ext ); fail: memFree( ext ); return UR_THROW; }
static int ssl_error( UThread* ut, const char* func, int err ) { return ur_error( ut, UR_ERR_INTERNAL, "%s: -0x%d", func, -err ); }
/* Recursively evaluate math expression. \param cell Cell to evaluate. \param res Result. \return UR_OK or UR_THROW. */ int calc_eval( UThread* ut, UCell* cell, double* res ) { switch( ur_type(cell) ) { case UT_WORD: { const UCell* val = ur_wordCell( ut, cell ); if( ! val ) return UR_THROW; if( ur_is(val, UT_DECIMAL) ) *res = ur_decimal(val); else if( ur_is(val, UT_INT) || ur_is(val, UT_CHAR) ) *res = (double) ur_int(val); else { return ur_error( ut, UR_ERR_SCRIPT, "Invalid word '%s", ur_wordCStr( cell ) ); } } break; case UT_DECIMAL: *res = ur_decimal(cell); break; case UT_INT: case UT_CHAR: *res = (double) ur_int(cell); break; case UT_BLOCK: case UT_PAREN: { UBlockIterM bi; double num = 0.0; double right; #define RIGHT_VAL \ if( ++bi.it == bi.end ) \ return ur_error( ut, UR_ERR_SCRIPT, "Expected operator r-value" ); \ if( ! calc_eval( ut, bi.it, &right ) ) \ return UR_THROW; if( ! ur_blkSliceM( ut, &bi, cell ) ) return UR_THROW; ur_foreach( bi ) { if( ur_is(bi.it, UT_WORD) ) { switch( ur_atom(bi.it) ) { case UR_ATOM_PLUS: RIGHT_VAL num += right; break; case UR_ATOM_MINUS: RIGHT_VAL num -= right; break; case UR_ATOM_ASTERISK: RIGHT_VAL num *= right; break; case UR_ATOM_SLASH: RIGHT_VAL num /= right; break; default: if( ! calc_eval( ut, bi.it, &num ) ) return UR_THROW; } } else if( ur_is(bi.it, UT_SETWORD) ) { cell = ur_wordCellM( ut, bi.it ); if( ! cell ) return UR_THROW; ur_setId( cell, UT_DECIMAL ); ur_decimal(cell) = num; } else { if( ! calc_eval( ut, bi.it, &num ) ) return UR_THROW; } } *res = num; } break; default: *res = 0.0; break; } return UR_OK; }
static int _execIO( UThread* ut, char* cmd, UCell* res, const UBuffer* in, UBuffer* out, UBuffer* err ) { HANDLE childStdInR; HANDLE childStdInW; HANDLE childStdOutR; HANDLE childStdOutW; HANDLE childStdErrR; HANDLE childStdErrW; SECURITY_ATTRIBUTES sec; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD flags = 0; sec.nLength = sizeof(SECURITY_ATTRIBUTES); sec.lpSecurityDescriptor = NULL; sec.bInheritHandle = TRUE; childStdOutR = childStdErrR = INVALID_HANDLE_VALUE; if( in ) { if( ! CreatePipe( &childStdInR, &childStdInW, &sec, 0 ) ) { fail0: return ur_error( ut, UR_ERR_INTERNAL, "CreatePipe failed\n" ); } // Child does not inherit our end of pipe. SetHandleInformation( childStdInW, HANDLE_FLAG_INHERIT, 0 ); } if( out ) { if( ! CreatePipe( &childStdOutR, &childStdOutW, &sec, 0 ) ) { fail1: if( in ) _closePipe( childStdInR, childStdInW ); goto fail0; } // Child does not inherit our end of pipe. SetHandleInformation( childStdOutR, HANDLE_FLAG_INHERIT, 0 ); flags = DETACHED_PROCESS; } if( err ) { if( ! CreatePipe( &childStdErrR, &childStdErrW, &sec, 0 ) ) { if( out ) _closePipe( childStdOutR, childStdOutW ); goto fail1; } // Child does not inherit our end of pipe. SetHandleInformation( childStdErrR, HANDLE_FLAG_INHERIT, 0 ); flags = DETACHED_PROCESS; } ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); if( in || out || err ) { si.hStdInput = in ? childStdInR : NULL; si.hStdOutput = out ? childStdOutW : GetStdHandle( STD_OUTPUT_HANDLE ); si.hStdError = err ? childStdErrW : GetStdHandle( STD_ERROR_HANDLE ); si.dwFlags = STARTF_USESTDHANDLES; } ZeroMemory( &pi, sizeof(pi) ); // Start the child process. if( ! CreateProcess( NULL, // No module name (use command line). TEXT(cmd), // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. TRUE, // Handle inheritance. flags, // Creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ) // Pointer to PROCESS_INFORMATION structure. ) { if( in ) _closePipe( childStdInR, childStdInW ); if( out ) _closePipe( childStdOutR, childStdOutW ); if( err ) _closePipe( childStdErrR, childStdErrW ); return ur_error( ut, UR_ERR_INTERNAL, "CreateProcess failed (%d).\n", GetLastError() ); } if( in ) { DWORD nw; CloseHandle( childStdInR ); WriteFile( childStdInW, in->ptr.v, (in->type == UT_STRING) ? in->used * in->elemSize : in->used, &nw, NULL ); CloseHandle( childStdInW ); } if( out || err ) { if( out ) CloseHandle( childStdOutW ); if( err ) CloseHandle( childStdErrW ); _readPipes( childStdOutR, out, childStdErrR, err ); if( out ) CloseHandle( childStdOutR ); if( err ) CloseHandle( childStdErrR ); } { DWORD code; // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); if( GetExitCodeProcess( pi.hProcess, &code ) ) { ur_setId(res, UT_INT); ur_int(res) = code; } else { ur_setId(res, UT_NONE); } } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return UR_OK; }