From d5834686ad14b66420060192445f06bce85db389 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 6 Nov 2010 19:14:50 +0800 Subject: [PATCH] Composite commit (GUI / Networking) - GUI Work, just fiddling with getting images supported - Networking: > libnet being built for networking helpers > IPStack is being partially reworked to support routes and more versatile naming of interfaces (with the ultimate goal of removing integer names) > Basic IRC client in the works (testing the networking stack with it) - Other Changes: > Cleanups to library code (implemented snprintf in libc) > Improved debugging and thread status naming in threads.c --- Kernel/include/threads.h | 16 +- Kernel/lib.c | 3 +- Kernel/threads.c | 4 +- Modules/IPStack/ipstack.h | 9 + Modules/IPStack/main.c | 81 +++++- Modules/IPStack/routing.c | 159 ++++++++++++ Modules/IPStack/tcp.c | 6 +- Usermode/Applications/axwin2_src/WM/common.h | 1 + .../Applications/axwin2_src/WM/decorator.c | 8 + .../Applications/axwin2_src/WM/interface.c | 8 + Usermode/Applications/axwin2_src/WM/video.c | 79 ++++++ Usermode/Applications/axwin2_src/WM/wm.c | 15 +- Usermode/Applications/irc_src/Makefile | 10 + Usermode/Applications/irc_src/main.c | 238 ++++++++++++++++++ Usermode/Libraries/libc.so_src/fileIO.c | 14 ++ Usermode/Libraries/libimage_sif.so_src/main.c | 25 +- Usermode/Libraries/libnet.so_src/Makefile | 12 + Usermode/Libraries/libnet.so_src/address.c | 168 +++++++++++++ Usermode/Libraries/libnet.so_src/net.h | 25 ++ Usermode/include/net.h | 1 + Usermode/include/stdio.h | 1 + 21 files changed, 855 insertions(+), 28 deletions(-) create mode 100644 Modules/IPStack/routing.c create mode 100644 Usermode/Applications/irc_src/Makefile create mode 100644 Usermode/Applications/irc_src/main.c create mode 100644 Usermode/Libraries/libnet.so_src/Makefile create mode 100644 Usermode/Libraries/libnet.so_src/address.c create mode 100644 Usermode/Libraries/libnet.so_src/net.h create mode 120000 Usermode/include/net.h diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h index 833a3c77..2b8f9fba 100644 --- a/Kernel/include/threads.h +++ b/Kernel/include/threads.h @@ -76,8 +76,20 @@ enum { THREAD_STAT_MUTEXSLEEP, // Mutex Sleep THREAD_STAT_WAITING, // ??? (Waiting for a thread) THREAD_STAT_PREINIT, // Being created - THREAD_STAT_ZOMBIE, // Died, just not removed - THREAD_STAT_DEAD // Why do we care about these??? + THREAD_STAT_ZOMBIE, // Died/Killed, but parent not informed + THREAD_STAT_DEAD, // Awaiting burial (free) + THREAD_STAT_BURIED // If it's still on the list here, something's wrong +}; +static const char * const casTHREAD_STAT[] = { + "THREAD_STAT_NULL", + "THREAD_STAT_ACTIVE", + "THREAD_STAT_SLEEPING", + "THREAD_STAT_MUTEXSLEEP", + "THREAD_STAT_WAITING", + "THREAD_STAT_PREINIT", + "THREAD_STAT_ZOMBIE", + "THREAD_STAT_DEAD", + "THREAD_STAT_BURIED" }; enum eFaultNumbers diff --git a/Kernel/lib.c b/Kernel/lib.c index 3a4f31f1..66c96603 100644 --- a/Kernel/lib.c +++ b/Kernel/lib.c @@ -477,7 +477,7 @@ char *strdup(const char *Str) strcpy(ret, Str); return ret; } -#endif +#else /** * \fn char *_strdup(const char *File, int Line, const char *Str) @@ -491,6 +491,7 @@ char *_strdup(const char *File, int Line, const char *Str) strcpy(ret, Str); return ret; } +#endif /** * \brief Split a string using the passed character diff --git a/Kernel/threads.c b/Kernel/threads.c index dd4f0d2b..b76fe592 100644 --- a/Kernel/threads.c +++ b/Kernel/threads.c @@ -865,7 +865,7 @@ void Threads_Dump(void) { Log(" %i (%i) - %s (CPU %i)", thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU); - Log(" State %i", thread->Status); + Log(" State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]); switch(thread->Status) { case THREAD_STAT_MUTEXSLEEP: @@ -909,7 +909,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) thread = gDeleteThreads->Next; if( IS_LOCKED(&gDeleteThreads->IsLocked) ) { // Only free if structure is unused // Set to dead - gDeleteThreads->Status = THREAD_STAT_DEAD; + gDeleteThreads->Status = THREAD_STAT_BURIED; // Free name if( IsHeap(gDeleteThreads->ThreadName) ) free(gDeleteThreads->ThreadName); diff --git a/Modules/IPStack/ipstack.h b/Modules/IPStack/ipstack.h index 43953942..20f645cf 100644 --- a/Modules/IPStack/ipstack.h +++ b/Modules/IPStack/ipstack.h @@ -17,6 +17,12 @@ typedef struct sSocketFile tSocketFile; typedef void (*tIPCallback)(tInterface *Interface, void *Address, int Length, void *Buffer); +enum eInterfaceTypes { + AF_NULL, + AF_INET4 = 4, // tIPv4 + AF_INET6 = 6 // tIPv6 +}; + union uIPv4 { Uint32 L; Uint8 B[4]; @@ -38,6 +44,8 @@ struct sInterface { tAdapter *Adapter; int TimeoutDelay; // Time in miliseconds before a packet times out int Type; // 0 for disabled, 4 for IPv4 and 6 for IPv6 + + //TODO: Remove explicit mentions of IPv4/IPv6 and make more general union { struct { tIPv6 Address; @@ -96,5 +104,6 @@ static const tMacAddr cMAC_BROADCAST = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}}; #define ntohl(v) BigEndian32(v) extern int IPStack_AddFile(tSocketFile *File); +extern int IPStack_GetAddressSize(int AddressType); #endif diff --git a/Modules/IPStack/main.c b/Modules/IPStack/main.c index fe4bf0f6..0deaf3a9 100644 --- a/Modules/IPStack/main.c +++ b/Modules/IPStack/main.c @@ -30,6 +30,7 @@ extern int IPv6_Initialise(); char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos); tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name); int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data); + int IPStack_AddInterface(char *Device); tAdapter *IPStack_GetAdapter(char *Path); char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos); @@ -51,6 +52,21 @@ tDevFS_Driver gIP_DriverInfo = { } }; tShortSpinlock glIP_Interfaces; +//! Loopback (127.0.0.0/8, ::1) Pseudo-Interface +tInterface gIP_LoopInterface = { + Node: { + ImplPtr: &gIP_LoopInterface, + Flags: VFS_FFLAG_DIRECTORY, + Size: -1, + NumACLs: 1, + ACLs: &gVFS_ACL_EveryoneRX, + ReadDir: IPStack_Iface_ReadDir, + FindDir: IPStack_Iface_FindDir, + IOCtl: IPStack_Iface_IOCtl + }, + Adapter: NULL, + Type: 0 +}; tInterface *gIP_Interfaces = NULL; tInterface *gIP_Interfaces_Last = NULL; int giIP_NextIfaceId = 1; @@ -67,12 +83,11 @@ int IPStack_Install(char **Arguments) { int i = 0; - // Layer 2 - Data Link Layer + // Layer 3 - Network Layer Protocols ARP_Initialise(); - // Layer 3 - Network Layer IPv4_Initialise(); IPv6_Initialise(); - // Layer 4 - Transport Layer + // Layer 4 - Transport Layer Protocols TCP_Initialise(); UDP_Initialise(); @@ -81,12 +96,19 @@ int IPStack_Install(char **Arguments) // Parse module arguments for( i = 0; Arguments[i]; i++ ) { - //if(strcmp(Arguments[i], "Device") == '=') { - // - //} + // TODO: + // Define interfaces by ,,, + // Where: + // - is the device path (E.g. /Devices/ne2k/0) + // - is a number (e.g. 4) or symbol (e.g. AF_INET4) + // - is a condensed hexadecimal stream (in big endian) + // (E.g. 0A000201 for 10.0.2.1 IPv4) + // - is the number of subnet bits (E.g. 24 for an IPv4 Class C) } } + gIP_LoopInterface.Adapter = IPStack_GetAdapter("/Devices/fifo/anon"); + DevFS_AddDevice( &gIP_DriverInfo ); return MODULE_ERR_OK; @@ -112,6 +134,17 @@ char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos) char *name; ENTER("pNode iPos", Node, Pos); + + // Routing Subdir + if( Pos == 0 ) { + return strdup("routes"); + } + // Pseudo Interfaces + if( Pos == 1 ) { + return strdup("lo"); + } + Pos -= 2; + // Traverse the list for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ; @@ -161,6 +194,16 @@ tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name) ENTER("pNode sName", Node, Name); + // Routing subdir + if( strcmp(Name, "routes") == 0 ) { + return &gIP_RouteNode; + } + + // Loopback + if( strcmp(Name, "lo") == 0 ) { + return &gIP_LoopInterface.Node; + } + i = 0; num = 0; while('0' <= Name[i] && Name[i] <= '9') { @@ -222,7 +265,10 @@ int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data) case 4: if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1); if( !CheckString( Data ) ) LEAVE_RET('i', -1); - tmp = IPStack_AddInterface(Data); + { + char name[4] = ""; + tmp = IPStack_AddInterface(Data, name); + } LEAVE_RET('i', tmp); } LEAVE('i', 0); @@ -513,7 +559,7 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data) * \fn int IPStack_AddInterface(char *Device) * \brief Adds an interface to the list */ -int IPStack_AddInterface(char *Device) +int IPStack_AddInterface(const char *Device, const char *Name) { tInterface *iface; tAdapter *card; @@ -522,7 +568,7 @@ int IPStack_AddInterface(char *Device) card = IPStack_GetAdapter(Device); - iface = malloc(sizeof(tInterface)); + iface = malloc(sizeof(tInterface) + strlen(Name)); if(!iface) { LEAVE('i', -2); return -2; // Return ERR_MYBAD @@ -652,3 +698,20 @@ tAdapter *IPStack_GetAdapter(char *Path) LEAVE('p', dev); return dev; } + +/** + * \brief Gets the size (in bytes) of a specified form of address + */ +int IPStack_GetAddressSize(int AddressType) +{ + switch(AddressType) + { + default: + case AF_NULL: + return 0; + case AF_INET4: + return sizeof(tIPv4); + case AF_INET6: + return sizeof(tIPv6); + } +} diff --git a/Modules/IPStack/routing.c b/Modules/IPStack/routing.c new file mode 100644 index 00000000..9678adad --- /dev/null +++ b/Modules/IPStack/routing.c @@ -0,0 +1,159 @@ +/* + * Acess2 IP Stack + * - Routing Tables + */ +#include "ipstack.h" +#include "link.h" + + +// === TYPES === +typedef struct sRoute { + struct sRoute *Next; + tVFS_Node Node; + + int AddressType; // 0: Invalid, 4: IPv4, 6: IPv4 + void *Network; // Pointer to tIPv4/tIPv6/... at end of structure + int SubnetBits; + void *NextHop; // Pointer to tIPv4/tIPv6/... at end of structure + tInterface *Interface; +} tRoute; + +// === PROTOTYPES === +// - Routes directory +char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos); +tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name); + int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data); + int IPStack_Route_Create(const char *InterfaceName); +// - Individual Routes +Uint64 IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data); + + +// === GLOBALS === + int giIP_NextRouteId = 1; +tRoute *gIP_Routes; +tRoute *gIP_RoutesEnd; +tVFS_Node gIP_RouteNode = { + Flags: VFS_FFLAG_DIRECTORY, + Size: -1, + NumACLs: 1, + ACLs: &gVFS_ACL_EveryoneRX, + ReadDir: IPStack_RouteDir_ReadDir, + FindDir: IPStack_RouteDir_FindDir, + IOCtl: IPStack_RouteDir_IOCtl +}; + +// === CODE === +/** + * \brief ReadDir for the /Devices/ip/routes/ directory + */ +char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos) +{ + tRoute *rt; + + for(rt = gIP_Routes; rt && Pos --; rt = rt->Next); + + if( !rt ) { + return NULL; + } + + { + int len = snprintf(NULL, 12, "%i", rt->Node.Inode); + char buf[len+1]; + sprintf(buf, "%i", rt->Node.Inode); + return strdup(buf); + } +} + +/** + * \brief FindDir for the /Devices/ip/routes/ directory + */ +tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name) +{ + int num = atoi(Name); + + // Zero is invalid, sorry :) + if( !num ) return NULL; + + // The list is inherently sorted, so we can do a quick search + for(rt = gIP_Routes; rt && rt->Node.Inode < num; rt = rt->Next); + // Fast fail on larger number + if( rt->Node.Inode > num ) + return NULL; + + return &rt->Node; +} + +/** + * \brief Names for interface IOCtl Calls + */ +static const char *casIOCtls_RouteDir[] = { + DRV_IOCTLNAMES, + "add_route" // Add a route - char *InterfaceName + NULL + }; + +int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data) +{ + switch(ID) + { + // --- Standard IOCtls (0-3) --- + case DRV_IOCTL_TYPE: + LEAVE('i', DRV_TYPE_MISC); + return DRV_TYPE_MISC; + + case DRV_IOCTL_IDENT: + tmp = ModUtil_SetIdent(Data, STR(IDENT)); + LEAVE('i', 1); + return 1; + + case DRV_IOCTL_VERSION: + LEAVE('x', VERSION); + return VERSION; + + case DRV_IOCTL_LOOKUP: + tmp = ModUtil_LookupString( (char**)casIOCtls_RouteDir, (char*)Data ); + LEAVE('i', tmp); + return tmp; + + case 4: // Add Route + if( !CheckString(Data) ) return -1; + return IPStack_Route_Create(Data); + } + return 0; +} + +/** + * \brief Create a new route entry + */ +int IPStack_Route_Create(const char *InterfaceName) +{ + tRoute *rt; + tInterface *iface; + int size; + + // Get interface + // Note: Oh man! This is such a hack + { + tVFS_Node *node = IPStack_Root_FindDir(NULL, InterfaceName); + if( !node ) return 0; + iface = node->ImplPtr; + } + + // Get the size of the specified address type + size = IPStack_GetAddressSize(iface->AddressType); + if( size == 0 ) { + return 0; + } + + // Allocate space + rt = calloc(1, sizeof(tRoute) + size*2 ); + + rt->Next = NULL; + //rt->Node + + rt->AddressType = iface->AddressType; + rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) ); + rt->SubnetBits = 0; + rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size ); + rt->Interface = iface; +} diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 8b486d23..99e6719f 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -881,7 +881,7 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) if(conn->State != TCP_ST_CLOSED) return -1; if(!CheckMem(Data, sizeof(Uint16))) return -1; conn->RemotePort = *(Uint16*)Data; - return 0; + return conn->RemotePort; case 6: // Set Remote IP if( conn->State != TCP_ST_CLOSED ) @@ -906,6 +906,10 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) TCP_StartConnection(conn); return 1; + + // Get recieve buffer length + case 8: + return conn->RecievedBuffer->Length; } return 0; diff --git a/Usermode/Applications/axwin2_src/WM/common.h b/Usermode/Applications/axwin2_src/WM/common.h index eb21f3c7..2df0b55a 100644 --- a/Usermode/Applications/axwin2_src/WM/common.h +++ b/Usermode/Applications/axwin2_src/WM/common.h @@ -31,6 +31,7 @@ extern void Video_Update(void); extern void Video_FillRect(short X, short Y, short W, short H, uint32_t Color); extern void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color); extern void Video_DrawText(short X, short Y, short W, short H, void *Font, int Point, uint32_t Color, char *Text); +extern void Video_DrawImage(short X, short Y, short W, short H, tImage *Image); // --- Debug Hack --- extern void _SysDebug(const char *Format, ...); #endif diff --git a/Usermode/Applications/axwin2_src/WM/decorator.c b/Usermode/Applications/axwin2_src/WM/decorator.c index 601f9535..228e6aa3 100644 --- a/Usermode/Applications/axwin2_src/WM/decorator.c +++ b/Usermode/Applications/axwin2_src/WM/decorator.c @@ -72,5 +72,13 @@ void Decorator_RenderWidget(tElement *Element) Element->Text ); break; + + case ELETYPE_IMAGE: + Video_DrawImage( + Element->CachedX, Element->CachedY, + Element->CachedW, Element->CachedH, + Element->Data + ); + break; } } diff --git a/Usermode/Applications/axwin2_src/WM/interface.c b/Usermode/Applications/axwin2_src/WM/interface.c index b71d9446..af02429a 100644 --- a/Usermode/Applications/axwin2_src/WM/interface.c +++ b/Usermode/Applications/axwin2_src/WM/interface.c @@ -1,6 +1,9 @@ /* * Acess GUI (AxWin) Version 2 * By John Hodge (thePowersGang) + * + * interface.c + * > Main Overarching UI */ #include "common.h" @@ -13,13 +16,18 @@ tElement *gpInterface_TabBar; tElement *gpInterface_TabContent; // === CODE === +/** + * \brief Initialise the UI + */ void Interface_Init(void) { tElement *area; tElement *btn, *text; + // Calculate sizes giInterface_Width = giScreenWidth/16; + // Set root window to no-border WM_SetFlags(NULL, 0); // -- Create Sidebar -- diff --git a/Usermode/Applications/axwin2_src/WM/video.c b/Usermode/Applications/axwin2_src/WM/video.c index d17e0e59..7b56df7d 100644 --- a/Usermode/Applications/axwin2_src/WM/video.c +++ b/Usermode/Applications/axwin2_src/WM/video.c @@ -5,6 +5,7 @@ #include "common.h" #include #include +#include // === PROTOTYPES === void Video_Setup(void); @@ -94,7 +95,85 @@ void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color) Video_FillRect(X+W-1, Y, 1, H, Color); } +/** + * \brief Draw text to the screen + */ void Video_DrawText(short X, short Y, short W, short H, void *Font, int Point, uint32_t Color, char *Text) { // TODO! } + +/** + * \brief Draw an image to the screen + * \todo Maybe have support for an offset in the image + */ +void Video_DrawImage(short X, short Y, short W, short H, tImage *Image) +{ + int x, y; + uint8_t *buf = (uint8_t *)(gpScreenBuffer + Y*giScreenWidth + X); + uint8_t *data = Image->Data; + + // Bounds Check + if( X >= giScreenWidth ) return ; + if( Y >= giScreenHeight ) return ; + + // Wrap to image size + if( W > Image->Width ) W = Image->Width; + if( H > Image->Height ) H = Image->Height; + + // Wrap to screen size + if( X + W > giScreenWidth ) W = giScreenWidth - X; + if( Y + H > giScreenHeight ) H = giScreenHeight - Y; + + switch( Image->Format ) + { + case IMGFMT_BGRA: + for( y = 0; y < H; y ++ ) + { + int r, g, b, a; // New + int or, og, ob; // Original + for( x = 0; x < W; x ++ ) { + b = data[x*4+0]; g = data[x*4+1]; r = data[x*4+2]; a = data[x*4+3]; + if( a == 0 ) continue; // 100% transparent + ob = buf[x*4+0]; og = buf[x*4+1]; or = buf[x*4+2]; + // Handle Alpha + switch(a) + { + // Transparent: Handled above + // Solid + case 0xFF: break; + // Half + case 0x80: + r = (or + r) / 2; + g = (og + g) / 2; + b = (ob + b) / 2; + break; + // General + default: + r = (or * (255-a) + r * a) / 255; + g = (og * (255-a) + g * a) / 255; + b = (ob * (255-a) + b * a) / 255; + break; + } + buf[x*4+0] = b; buf[x*4+1] = g; buf[x*4+2] = r; + } + data += Image->Width * 4; + buf += giScreenWidth * 4; + } + break; + + // RGB + case IMGFMT_RGB: + for( y = 0; y < H; y ++ ) + { + for( x = 0; x < W; x ++ ) { + buf[x*4+0] = data[x*3+2]; // Blue + buf[x*4+1] = data[x*3+1]; // Green + buf[x*4+2] = data[x*3+0]; // Red + } + data += W * 3; + buf += giScreenWidth * 4; + } + break; + } +} diff --git a/Usermode/Applications/axwin2_src/WM/wm.c b/Usermode/Applications/axwin2_src/WM/wm.c index a8fc96db..9bd5aa43 100644 --- a/Usermode/Applications/axwin2_src/WM/wm.c +++ b/Usermode/Applications/axwin2_src/WM/wm.c @@ -6,7 +6,7 @@ */ #include "common.h" #include -#include +#include #include "wm.h" // === IMPORTS === @@ -90,6 +90,10 @@ void WM_SetSize(tElement *Element, int Size) return ; } +/** + * \brief Set the text field of an element + * \note Used for the image path on ELETYPE_IMAGE + */ void WM_SetText(tElement *Element, char *Text) { if(!Element) return ; @@ -125,6 +129,11 @@ void WM_SetText(tElement *Element, char *Text) } // --- Pre-Rendering --- +/** + * \name Pre-Rendering + * \brief Updates the element positions and sizes + * \{ + */ /** * \brief Updates the dimensions of an element * @@ -286,7 +295,6 @@ void WM_UpdatePosition(tElement *Element) ); } - /** * \brief Update the minimum dimensions of the element * \note Called after a child's minimum dimensions have changed @@ -331,6 +339,9 @@ void WM_UpdateMinDims(tElement *Element) // Recurse upwards WM_UpdateMinDims(Element->Parent); } +/** + * \} + */ // --- Render --- void WM_RenderWidget(tElement *Element) diff --git a/Usermode/Applications/irc_src/Makefile b/Usermode/Applications/irc_src/Makefile new file mode 100644 index 00000000..98fa2bb0 --- /dev/null +++ b/Usermode/Applications/irc_src/Makefile @@ -0,0 +1,10 @@ +# Project: IRC Client + +-include ../Makefile.cfg + +LDFLAGS += -lnet + +OBJ = main.o +BIN = ../ls + +-include ../Makefile.tpl diff --git a/Usermode/Applications/irc_src/main.c b/Usermode/Applications/irc_src/main.c new file mode 100644 index 00000000..c202c6bd --- /dev/null +++ b/Usermode/Applications/irc_src/main.c @@ -0,0 +1,238 @@ +/* + * Acess2 IRC Client + */ +#include +#include +#include +#include +#include + +#define BUFSIZ 1023 + +// === TYPES === +typedef struct sServer { + int FD; + char InBuf[BUFSIZ+1]; + int ReadPos; +} tServer; + +// === PROTOTYPES === + int ParseArguments(int argc, const char *argv[]); +void ProcessIncoming(tServer *Server); + int writef(int FD, const char *Format, ...); + int OpenTCP(const char *AddressString, short PortNumber); + +// === GLOBALS === +char *gsUsername = "root"; +char *gsHostname = "acess"; +char *gsRemoteAddress = NULL; +char *gsRealName = "Acess2 IRC Client"; +char *gsNickname = "acess"; +short giRemotePort = 6667; + +// ==== CODE ==== +int main(int argc, const char *argv[], const char *envp[]) +{ + int tmp; + tServer srv; + + memset(&srv, 0, sizeof(srv)); + + if( (tmp = ParseArguments(argc, argv)) ) { + return tmp; + } + + srv.FD = OpenTCP( gsRemoteAddress, giRemotePort ); + if( srv.FD == -1 ) { + fprintf(stderr, "Unable to create socket\n"); + return -1; + } + + writef(srv.FD, "USER %s %s %s : %s\n", gsUsername, gsHostname, gsRemoteAddress, gsRealName); + writef(srv.FD, "NICK %s", gsNickname); + + ProcessIncoming(&srv); + + close(srv.FD); + return 0; +} + +/** + * \todo Actually implement correctly :) + */ +int ParseArguments(int argc, const char *argv[]) +{ + gsRemoteAddress = "130.95.13.18"; // irc.ucc.asn.au + + return 0; +} + +void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message) +{ + printf("%p: %s => %s\t%s\n", Server, Src, Dest, Message); +} + +/** + * \brief Read a space-separated value from a string + */ +char *GetValue(char *Src, int *Ofs) +{ + int pos = *Ofs; + char *ret = Src + pos; + char *end; + + while( *ret == ' ' ) ret ++; + + end = strchr(ret, ' '); + if( end ) { + *end = '\0'; + } + else { + end = ret + strlen(ret) - 1; + } + *Ofs = end - Src + 1; + + return ret; +} + +/** + */ +void ParseServerLine(tServer *Server, char *Line) +{ + int pos; + char *ident, *cmd; + if( *Line == ':' ) { + // Message + ident = GetValue(Line, &pos); + pos ++; // Space + cmd = GetValue(Line, &pos); + + if( strcmp(cmd, "PRIVMSG") == 0 ) { + char *dest, *message; + pos ++; + dest = GetValue(Line, &pos); + pos ++; + if( Line[pos] == ':' ) { + message = Line + pos + 1; + } + else { + message = GetValue(Line, &pos); + } + Cmd_PRIVMSG(Server, dest, ident, message); + } + } + else { + // Command to client + } +} + +/** + * \brief Process incoming lines from the server + */ +void ProcessIncoming(tServer *Server) +{ + char *ptr, *newline; + int len; + + // While there is data in the buffer, read it into user memory and + // process it line by line + // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer + // - Used to avoid blocking + while( ioctl(Server->FD, 8, NULL) ) + { + // Read data + len = read(Server->FD, BUFSIZ - Server->ReadPos, Server->InBuf + Server->ReadPos); + Server->InBuf[Server->ReadPos + len] = '\0'; + + // Break into lines + ptr = Server->InBuf; + while( (newline = strchr(ptr, '\n')) ) + { + *newline = '\0'; + printf("%s\n", ptr); + ParseServerLine(Server, ptr); + ptr = newline + 1; + } + + // Handle incomplete lines + if( ptr - Server->InBuf < len + Server->ReadPos ) { + Server->ReadPos = ptr - Server->InBuf; + memcpy(Server->InBuf, ptr, Server->ReadPos); + } + else { + Server->ReadPos = 0; + } + } +} + +/** + * \brief Write a formatted string to a file descriptor + * + */ +int writef(int FD, const char *Format, ...) +{ + va_list args; + int len; + + va_start(args, Format); + len = vsnprintf(NULL, 1000, Format, args); + va_end(args); + + { + char buf[len+1]; + va_start(args, Format); + vsnprintf(buf, len+1, Format, args); + va_end(args); + + return write(FD, len, buf); + } +} + +/** + * \brief Initialise a TCP connection to \a AddressString on port \a PortNumber + */ +int OpenTCP(const char *AddressString, short PortNumber) +{ + int fd, addrType, iface; + char addrBuffer[8]; + + // Parse IP Address + addrType = Net_ParseAddress(AddressString, addrBuffer); + if( addrType == 0 ) { + fprintf(stderr, "Unable to parse '%s' as an IP address\n", AddressString); + return -1; + } + + // Finds the interface for the destination address + iface = Net_GetInterface(addrType, addrBuffer); + if( iface == -1 ) { + fprintf(stderr, "Unable to find a route to '%s'\n", AddressString); + return -1; + } + + // Open client socket + // TODO: Move this out to libnet? + { + int len = snprintf(NULL, 100, "/Devices/ip/%i/tcpc", iface); + char path[len+1]; + snprintf(path, 100, "/Devices/ip/%i/tcpc", iface); + fd = open(path, OPENFLAG_READ|OPENFLAG_WRITE); + } + + if( fd == -1 ) { + return -1; + } + + // Set remote port and address + ioctl(fd, 5, &PortNumber); + ioctl(fd, 6, addrBuffer); + + // Connect + if( ioctl(fd, 7, NULL) == 0 ) { + // Shouldn't happen :( + return -1; + } + + // Return descriptor + return fd; +} diff --git a/Usermode/Libraries/libc.so_src/fileIO.c b/Usermode/Libraries/libc.so_src/fileIO.c index 7149b3eb..f26fadac 100644 --- a/Usermode/Libraries/libc.so_src/fileIO.c +++ b/Usermode/Libraries/libc.so_src/fileIO.c @@ -546,3 +546,17 @@ EXPORT int sprintf(char *buf, const char *format, ...) va_end(args); return ret; } + +/** + * \fn EXPORT int snprintf(const char *buf, size_t maxlen, char *format, ...) + * \brief Print a formatted string to a buffer + */ +EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...) +{ + int ret; + va_list args; + va_start(args, format); + ret = vsnprintf((char*)buf, maxlen, (char*)format, args); + va_end(args); + return ret; +} diff --git a/Usermode/Libraries/libimage_sif.so_src/main.c b/Usermode/Libraries/libimage_sif.so_src/main.c index 455d3bce..7b076a3b 100644 --- a/Usermode/Libraries/libimage_sif.so_src/main.c +++ b/Usermode/Libraries/libimage_sif.so_src/main.c @@ -21,7 +21,7 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) uint16_t flags; uint16_t w, h; int ofs, i; - tImage_SIF *ret; + tImage *ret; int bRevOrder; int fileOfs = 0; int comp, fmt; @@ -46,21 +46,15 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) w = *(uint16_t*)Buffer+fileOfs; fileOfs += 2; h = *(uint16_t*)Buffer+fileOfs; fileOfs += 2; - - // Allocate space - ret = calloc(1, sizeof(tImage) + w * h * sampleSize); - ret->Width = w; - ret->Height = h; - // Get image format switch(fmt) { - case 0: // ARGB - ret->Format = IMGFMT_ARGB; + case 0: // ARGB 32-bit Little Endian + fmt = IMGFMT_BGRA; sampleSize = 4; break; - case 1: // RGB - ret->Format = IMGFMT_RGB; + case 1: // RGB 24-bit big endian + fmt = IMGFMT_RGB; sampleSize = 3; break; default: @@ -68,6 +62,12 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) return NULL; } + // Allocate space + ret = calloc(1, sizeof(tImage) + w * h * sampleSize); + ret->Width = w; + ret->Height = h; + ret->Format = fmt; + switch(comp) { // Uncompressed 32-bpp data @@ -89,6 +89,7 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) uint8_t len; if( fileOfs + 1 > Size ) return ret; len = *(uint8_t*)Buffer+fileOfs; fileOfs += 1; + // Verbatim if(len & 0x80) { len &= 0x7F; if( fileOfs + len*sampleSize > Size ) { @@ -100,6 +101,7 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) } ofs += len; } + // RLE else { uint8_t tmp[sampleSize]; @@ -118,6 +120,7 @@ tImage *Image_SIF_Parse(void *Buffer, size_t Size) return ret; // Channel 1.7.8 RLE + // - Each channel is separately 1.7 RLE compressed case 3: // Alpha, Red, Green, Blue for( i = 0; i < sampleSize; i++ ) diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile new file mode 100644 index 00000000..f92e7bc4 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -0,0 +1,12 @@ +# Acess 2 - Networking Helpers + +include ../Makefile.cfg + +CPPFLAGS += +CFLAGS += -Wall +LDFLAGS += -lc -soname libnet.so + +OBJ = address.o +BIN = ../libnet.so + +include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/address.c b/Usermode/Libraries/libnet.so_src/address.c new file mode 100644 index 00000000..2b58444d --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/address.c @@ -0,0 +1,168 @@ +/* + * Acess2 Networking Toolkit + * By John Hodge (thePowersGang) + * + * address.c + * - Address Parsing + */ +#include +#include +#define DEBUG 0 + +/** + * \brief Read an IPv4 Address + * \param String IPv4 dotted decimal address + * \param Addr Output 32-bit representation of IP address + * \return Boolean success + */ +static int Net_ParseIPv4Addr(const char *String, uint8_t *Addr) +{ + int i = 0; + int j; + int val; + + for( j = 0; String[i] && j < 4; j ++ ) + { + val = 0; + for( ; String[i] && String[i] != '.'; i++ ) + { + if('0' > String[i] || String[i] > '9') { + #if DEBUG + printf("0 255) { + #if DEBUG + printf("val > 255 (%i)\n", val); + #endif + return 0; + } + Addr[j] = val; + + if(String[i] == '.') + i ++; + } + if( j != 4 ) { + #if DEBUG + printf("4 parts expected, %i found\n", j); + #endif + return 0; + } + if(String[i] != '\0') { + #if DEBUG + printf("EOS != '\\0', '%c'\n", String[i]); + #endif + return 0; + } + return 1; +} + +/** + * \brief Read an IPv6 Address + * \param String IPv6 colon-hex representation + * \param Addr Output 128-bit representation of IP address + * \return Boolean success + */ +static int Net_ParseIPv6Addr(const char *String, uint8_t *Addr) +{ + int i = 0; + int j, k; + int val, split = -1, end; + uint16_t hi[8], low[8]; + + for( j = 0; String[i] && j < 8; j ++ ) + { + if(String[i] == ':') { + if(split != -1) { + #if DEBUG + printf("Two '::'s\n"); + #endif + return 0; + } + split = j; + i ++; + continue; + } + + val = 0; + for( k = 0; String[i] && String[i] != ':'; i++, k++ ) + { + val *= 16; + if('0' <= String[i] && String[i] <= '9') + val += String[i] - '0'; + else if('A' <= String[i] && String[i] <= 'F') + val += String[i] - 'A' + 10; + else if('a' <= String[i] && String[i] <= 'f') + val += String[i] - 'a' + 10; + else { + #if DEBUG + printf("%c unexpected\n", String[i]); + #endif + return 0; + } + } + + if(val > 0xFFFF) { + #if DEBUG + printf("val (0x%x) > 0xFFFF\n", val); + #endif + return 0; + } + + if(split == -1) + hi[j] = val; + else + low[j-split] = val; + + if( String[i] == ':' ) { + i ++; + } + } + end = j; + + // Create final address + // - First section + for( j = 0; j < split; j ++ ) + { + Addr[j*2] = hi[j]>>8; + Addr[j*2+1] = hi[j]&0xFF; + } + // - Zero region + for( ; j < 8 - (end - split); j++ ) + { + Addr[j*2] = 0; + Addr[j*2+1] = 0; + } + // - Tail section + k = 0; + for( ; j < 8; j ++, k++) + { + Addr[j*2] = hi[k]>>8; + Addr[j*2+1] = hi[k]&0xFF; + } + + return 1; +} + +/** + * \brief Parse an address from a string + * \param String String containing an IPv4/IPv6 address + * \param Addr Buffer for the address (must be >= 16 bytes) + * \return Address type + * \retval 0 Unknown address type + * \retval 4 IPv4 Address + * \retval 6 IPv6 Address + */ +int Net_ParseAddress(const char *String, void *Addr) +{ + if( Net_ParseIPv4Addr(String, Addr) ) + return 4; + + if( Net_ParseIPv6Addr(String, Addr) ) + return 6; + + return 0; +} diff --git a/Usermode/Libraries/libnet.so_src/net.h b/Usermode/Libraries/libnet.so_src/net.h new file mode 100644 index 00000000..05deb9f9 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/net.h @@ -0,0 +1,25 @@ +/* + * Acess2 Common Networking Library + * By John Hodge (thePowersGang) + */ + +#ifndef __LIBNET_H_ +#define __LIBNET_H_ + +/** + * \brief Parse a string as an IP Address + * \param String Input string + * \param Addr Output binary format of the address + * \return Address family (0: Invalid, 4: IPv4, 6: IPv6) + */ +extern int Net_ParseAddress(const char *String, void *Addr); + +/** + * \brief Get the interface required to reach \a Addr + * \param AddrType Addresss Family (4: IPv4, 6: IPv6) + * \param Addr Address in binary format + * \return Interface number + */ +extern int Net_GetInterface(int AddrType, void *Addr); + +#endif diff --git a/Usermode/include/net.h b/Usermode/include/net.h new file mode 120000 index 00000000..be2d196c --- /dev/null +++ b/Usermode/include/net.h @@ -0,0 +1 @@ +../Libraries/libnet.so_src/net.h \ No newline at end of file diff --git a/Usermode/include/stdio.h b/Usermode/include/stdio.h index 1223fe8c..ce42a159 100644 --- a/Usermode/include/stdio.h +++ b/Usermode/include/stdio.h @@ -19,6 +19,7 @@ extern int printf(const char *format, ...); extern int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args); extern int vsprintf(char *buf, const char *format, va_list args); extern int sprintf(char *buf, const char *format, ...); +extern int snprintf(char *buf, size_t maxlen, const char *format, ...); extern FILE *fopen(const char *file, const char *mode); extern FILE *freopen(const char *file, const char *mode, FILE *fp); -- 2.20.1