12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- unsocket.c
- Abstract:
- This module implements support for Unix domain sockets.
- Author:
- Evan Green 15-Jan-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "iop.h"
- #include "unsocket.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the default maximum pending send size for a Unix socket. This is
- // how much data a socket can send without the receiver receiving it before the
- // sender is blocked.
- //
- #define UNIX_SOCKET_DEFAULT_SEND_MAX 131072
- //
- // Define the maximum number of file descriptors that can be passed in a
- // rights control message.
- //
- #define UNIX_SOCKET_MAX_CONTROL_HANDLES 256
- //
- // Define the maximum size of control data.
- //
- #define UNIX_SOCKET_MAX_CONTROL_DATA 32768
- //
- // Define local socket flags.
- //
- //
- // This flag is set when the socket should send and receive credentials in
- // control data automatically.
- //
- #define UNIX_SOCKET_FLAG_SEND_CREDENTIALS 0x00000001
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _UNIX_SOCKET_STATE {
- UnixSocketStateInvalid,
- UnixSocketStateInitialized,
- UnixSocketStateBound,
- UnixSocketStateListening,
- UnixSocketStateConnected,
- UnixSocketStateShutdownWrite,
- UnixSocketStateShutdownRead,
- UnixSocketStateShutdown,
- UnixSocketStateClosed
- } UNIX_SOCKET_STATE, *PUNIX_SOCKET_STATE;
- typedef struct _UNIX_SOCKET UNIX_SOCKET, *PUNIX_SOCKET;
- /*++
- Structure Description:
- This structure defines a set of Unix socket credentials. This structure
- matches up with struct ucred in the C library.
- Members:
- ProcessId - Stores the ID of the process that sent the message, or -1 if
- not set.
- UserId - Stores the user ID of the process that sent the message, or -1 if
- not set.
- GroupId - Stores the group ID of the process that sent the message, or -1
- if not set.
- --*/
- typedef struct _UNIX_SOCKET_CREDENTIALS {
- PROCESS_ID ProcessId;
- USER_ID UserId;
- GROUP_ID GroupId;
- } UNIX_SOCKET_CREDENTIALS, *PUNIX_SOCKET_CREDENTIALS;
- /*++
- Structure Description:
- This structure defines a Unix socket object.
- Members:
- ListEntry - Stores pointers to the next and previous packets to be received.
- Data - Stores a pointer to the data.
- Length - Stores the length of the data, in bytes.
- Offset - Stores the number of bytes the receiver has already returned.
- Sender - Stores a pointer to the sender. This structure holds a reference
- to the sender which must be released when this structure is destroyed.
- Credentials - Stores the credentials of the sender.
- Handles - Stores an optional pointer to an array of file handles being
- passed in this message.
- HandleCount - Stores the number of file handles being passed in this
- message.
- --*/
- typedef struct _UNIX_SOCKET_PACKET {
- LIST_ENTRY ListEntry;
- PVOID Data;
- UINTN Length;
- UINTN Offset;
- PUNIX_SOCKET Sender;
- UNIX_SOCKET_CREDENTIALS Credentials;
- PIO_HANDLE *Handles;
- UINTN HandleCount;
- } UNIX_SOCKET_PACKET, *PUNIX_SOCKET_PACKET;
- /*++
- Structure Description:
- This structure defines a Unix socket object.
- Members:
- KernelSocket - Stores the standard kernel socket portions.
- Lock - Stores a pointer to the lock that protects this socket.
- State - Stores the current state of the socket.
- Name - Stores a pointer to the name of the socket, allocated from paged
- pool.
- NameSize - Stores the size of the name buffer in bytes, including the null
- terminator.
- PathPoint - Stores a pointer to the path point where this socket resides if
- it is bound. The socket holds a reference on the path point.
- ReceiveList - Stores the head of the list of outgoing packets. Entries on
- this list are Unix socket packets.
- SendListMax - Stores the maximum number of bytes that can be queued on the
- send list before the socket blocks.
- SendListSize - Stores the current number of bytes queued to be sent.
- MaxBacklog - Stores the maximum incoming connection backlog.
- CurrentBacklog - Stores the current number of incoming connections.
- ConnectionListEntry - Stores a dual-purpose list entry. For servers, this
- represents the head of the list of sockets trying to connect to it.
- For clients, this is the list entry that goes on the server's incoming
- connection list.
- Remote - Stores a pointer to the other side of the connection, for a
- connection oriented socket.
- Flags - Stores a bitfield of flags governing the socket. See
- UNIX_SOCKET_FLAG_* definitions.
- Credentials - Stores the credentials of the process when the socket was
- connected.
- --*/
- struct _UNIX_SOCKET {
- SOCKET KernelSocket;
- PQUEUED_LOCK Lock;
- UNIX_SOCKET_STATE State;
- PSTR Name;
- UINTN NameSize;
- PATH_POINT PathPoint;
- LIST_ENTRY ReceiveList;
- UINTN SendListMax;
- UINTN SendListSize;
- UINTN MaxBacklog;
- UINTN CurrentBacklog;
- LIST_ENTRY ConnectionListEntry;
- PUNIX_SOCKET Remote;
- ULONG Flags;
- UNIX_SOCKET_CREDENTIALS Credentials;
- };
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- IopUnixSocketEnsureConnected (
- PUNIX_SOCKET Socket,
- BOOL Write
- );
- VOID
- IopUnixSocketFlushData (
- PUNIX_SOCKET Socket
- );
- KSTATUS
- IopUnixSocketCreatePacket (
- PUNIX_SOCKET Sender,
- PIO_BUFFER IoBuffer,
- UINTN Offset,
- UINTN DataSize,
- PUNIX_SOCKET_PACKET *NewPacket
- );
- VOID
- IopUnixSocketDestroyPacket (
- PUNIX_SOCKET_PACKET Packet
- );
- KSTATUS
- IopUnixSocketSendControlData (
- BOOL FromKernelMode,
- PUNIX_SOCKET Sender,
- PUNIX_SOCKET_PACKET Packet,
- PVOID ControlData,
- UINTN ControlDataSize
- );
- KSTATUS
- IopUnixSocketReceiveControlData (
- BOOL FromKernelMode,
- PUNIX_SOCKET Socket,
- PUNIX_SOCKET_PACKET Packet,
- PSOCKET_IO_PARAMETERS Parameters
- );
- VOID
- IopUnixSocketInitializeCredentials (
- PUNIX_SOCKET Socket
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- IopCreateUnixSocketPair (
- NET_SOCKET_TYPE Type,
- ULONG Protocol,
- ULONG OpenFlags,
- PIO_HANDLE NewSockets[2]
- )
- /*++
- Routine Description:
- This routine creates a pair of connected local domain sockets.
- Arguments:
- Type - Supplies the socket connection type.
- Protocol - Supplies the raw protocol value for this socket used on the
- network. This value is network specific.
- OpenFlags - Supplies a bitfield of open flags governing the new handles.
- See OPEN_FLAG_* definitions.
- NewSockets - Supplies an array where the two pointers to connected sockets
- will be returned.
- Return Value:
- Status code.
- --*/
- {
- PIO_HANDLE IoHandles[2];
- PSOCKET Sockets[2];
- KSTATUS Status;
- PUNIX_SOCKET UnixSockets[2];
- IoHandles[0] = NULL;
- IoHandles[1] = NULL;
- Status = IoSocketCreate(NetDomainLocal,
- Type,
- Protocol,
- OpenFlags,
- &(IoHandles[0]));
- if (!KSUCCESS(Status)) {
- goto CreateUnixSocketPairEnd;
- }
- Status = IoSocketCreate(NetDomainLocal,
- Type,
- Protocol,
- OpenFlags,
- &(IoHandles[1]));
- if (!KSUCCESS(Status)) {
- goto CreateUnixSocketPairEnd;
- }
- Status = IoGetSocketFromHandle(IoHandles[0], &(Sockets[0]));
- ASSERT(KSUCCESS(Status));
- Status = IoGetSocketFromHandle(IoHandles[1], &(Sockets[1]));
- ASSERT(KSUCCESS(Status));
- UnixSockets[0] = (PUNIX_SOCKET)(Sockets[0]);
- UnixSockets[1] = (PUNIX_SOCKET)(Sockets[1]);
- //
- // Connect the two sockets directly together.
- //
- UnixSockets[0]->Remote = UnixSockets[1];
- IoSocketAddReference(Sockets[1]);
- UnixSockets[1]->Remote = UnixSockets[0];
- IoSocketAddReference(Sockets[0]);
- UnixSockets[0]->State = UnixSocketStateConnected;
- UnixSockets[1]->State = UnixSocketStateConnected;
- IopUnixSocketInitializeCredentials(UnixSockets[0]);
- IopUnixSocketInitializeCredentials(UnixSockets[1]);
- Status = STATUS_SUCCESS;
- CreateUnixSocketPairEnd:
- if (!KSUCCESS(Status)) {
- if (IoHandles[0] != NULL) {
- IoClose(IoHandles[0]);
- IoHandles[0] = NULL;
- }
- if (IoHandles[1] != NULL) {
- IoClose(IoHandles[1]);
- IoHandles[1] = NULL;
- }
- }
- NewSockets[0] = IoHandles[0];
- NewSockets[1] = IoHandles[1];
- return Status;
- }
- KSTATUS
- IopCreateUnixSocket (
- NET_DOMAIN_TYPE Domain,
- NET_SOCKET_TYPE Type,
- ULONG Protocol,
- PSOCKET *NewSocket
- )
- /*++
- Routine Description:
- This routine creates a new Unix socket object.
- Arguments:
- Domain - Supplies the network domain to use on the socket.
- Type - Supplies the socket connection type.
- Protocol - Supplies the raw protocol value for this socket used on the
- network. This value is network specific.
- NewSocket - Supplies a pointer where a pointer to a newly allocated
- socket structure will be returned. The caller is responsible for
- allocating the socket (and potentially a larger structure for its own
- context). The kernel will fill in the standard socket structure after
- this routine returns.
- Return Value:
- Status code.
- --*/
- {
- PUNIX_SOCKET Socket;
- KSTATUS Status;
- ASSERT(Domain == NetDomainLocal);
- Socket = MmAllocatePagedPool(sizeof(UNIX_SOCKET),
- UNIX_SOCKET_ALLOCATION_TAG);
- if (Socket == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateUnixSocketEnd;
- }
- RtlZeroMemory(Socket, sizeof(UNIX_SOCKET));
- Socket->KernelSocket.Protocol = Protocol;
- Socket->KernelSocket.ReferenceCount = 1;
- Socket->KernelSocket.IoState = IoCreateIoObjectState(FALSE);
- if (Socket->KernelSocket.IoState == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateUnixSocketEnd;
- }
- IoSetIoObjectState(Socket->KernelSocket.IoState,
- POLL_EVENT_IN | POLL_EVENT_OUT,
- FALSE);
- Socket->Lock = KeCreateQueuedLock();
- if (Socket->Lock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateUnixSocketEnd;
- }
- Socket->State = UnixSocketStateInitialized;
- INITIALIZE_LIST_HEAD(&(Socket->ReceiveList));
- INITIALIZE_LIST_HEAD(&(Socket->ConnectionListEntry));
- Socket->SendListMax = UNIX_SOCKET_DEFAULT_SEND_MAX;
- Socket->Credentials.ProcessId = -1;
- Socket->Credentials.UserId = -1;
- Socket->Credentials.GroupId = -1;
- Status = STATUS_SUCCESS;
- CreateUnixSocketEnd:
- if (!KSUCCESS(Status)) {
- if (Socket != NULL) {
- if (Socket->Lock != NULL) {
- KeDestroyQueuedLock(Socket->Lock);
- }
- if (Socket->KernelSocket.IoState != NULL) {
- IoDestroyIoObjectState(Socket->KernelSocket.IoState);
- }
- MmFreePagedPool(Socket);
- Socket = NULL;
- }
- }
- *NewSocket = &(Socket->KernelSocket);
- return Status;
- }
- VOID
- IopDestroyUnixSocket (
- PSOCKET Socket
- )
- /*++
- Routine Description:
- This routine destroys the Unix socket object.
- Arguments:
- Socket - Supplies a pointer to the socket.
- Return Value:
- None.
- --*/
- {
- PUNIX_SOCKET UnixSocket;
- UnixSocket = (PUNIX_SOCKET)Socket;
- ASSERT(Socket->Domain == NetDomainLocal);
- ASSERT(UnixSocket->CurrentBacklog == 0);
- ASSERT(UnixSocket->SendListSize == 0);
- ASSERT(LIST_EMPTY(&(UnixSocket->ReceiveList)) != FALSE);
- if (UnixSocket->PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&(UnixSocket->PathPoint));
- UnixSocket->PathPoint.PathEntry = NULL;
- }
- if (UnixSocket->Name != NULL) {
- MmFreePagedPool(UnixSocket->Name);
- }
- if (UnixSocket->Lock != NULL) {
- KeDestroyQueuedLock(UnixSocket->Lock);
- }
- UnixSocket->State = UnixSocketStateInvalid;
- MmFreePagedPool(UnixSocket);
- return;
- }
- KSTATUS
- IopUnixSocketBindToAddress (
- BOOL FromKernelMode,
- PIO_HANDLE Handle,
- PNETWORK_ADDRESS Address,
- PSTR Path,
- UINTN PathSize
- )
- /*++
- Routine Description:
- This routine binds the Unix socket to the given path and starts listening
- for client requests.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the request is coming
- from kernel mode or user mode. This value affects the root path node
- to traverse for local domain sockets.
- Handle - Supplies a pointer to the handle to bind.
- Address - Supplies a pointer to the address to bind the socket to.
- Path - Supplies an optional pointer to a path, required if the network
- address is a local socket.
- PathSize - Supplies the size of the path in bytes including the null
- terminator.
- Return Value:
- Status code.
- --*/
- {
- SOCKET_CREATION_PARAMETERS CreationParameters;
- PFILE_OBJECT FileObject;
- ULONG OpenFlags;
- PSTR PathCopy;
- PATH_POINT PathPoint;
- PSOCKET Socket;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- PSTR WalkedPath;
- ULONG WalkedPathSize;
- PathCopy = NULL;
- IO_INITIALIZE_PATH_POINT(&PathPoint);
- UnixSocket = NULL;
- FileObject = Handle->FileObject;
- Status = IoGetSocketFromHandle(Handle, &Socket);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- ASSERT(Socket->Domain == NetDomainLocal);
- UnixSocket = (PUNIX_SOCKET)Socket;
- KeAcquireQueuedLock(UnixSocket->Lock);
- //
- // If the socket isn't a fresh one, fail.
- //
- if (UnixSocket->State != UnixSocketStateInitialized) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketBindToAddressEnd;
- }
- if (PathSize != 0) {
- if (FromKernelMode != FALSE) {
- PathCopy = MmAllocatePagedPool(PathSize,
- UNIX_SOCKET_ALLOCATION_TAG);
- if (PathCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UnixSocketBindToAddressEnd;
- }
- RtlCopyMemory(PathCopy, Path, PathSize);
- //
- // If the request came from user mode, copy the string.
- //
- } else {
- Status = MmCreateCopyOfUserModeString(Path,
- PathSize,
- UNIX_SOCKET_ALLOCATION_TAG,
- &PathCopy);
- if (!KSUCCESS(Status)) {
- goto UnixSocketBindToAddressEnd;
- }
- }
- }
- //
- // If the caller wants an anonymous socket, then just bind it.
- //
- if ((PathSize == 0) || (PathCopy[0] == '\0')) {
- UnixSocket->State = UnixSocketStateBound;
- Status = STATUS_SUCCESS;
- goto UnixSocketBindToAddressEnd;
- }
- //
- // "Create" a socket at the given path, but use this socket rather than
- // actually creating a new one. This opens up a new handle whose path entry
- // points to the named object.
- //
- RtlZeroMemory(&CreationParameters, sizeof(SOCKET_CREATION_PARAMETERS));
- CreationParameters.ExistingSocket = Socket;
- WalkedPath = PathCopy;
- WalkedPathSize = PathSize;
- OpenFlags = Handle->OpenFlags | OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS;
- Status = IopPathWalk(FromKernelMode,
- NULL,
- &WalkedPath,
- &WalkedPathSize,
- OpenFlags,
- IoObjectSocket,
- &CreationParameters,
- FileObject->Properties.Permissions,
- &PathPoint);
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_FILE_EXISTS) {
- Status = STATUS_ADDRESS_IN_USE;
- }
- goto UnixSocketBindToAddressEnd;
- }
- Status = IopCheckPermissions(FromKernelMode,
- &PathPoint,
- IO_ACCESS_READ | IO_ACCESS_WRITE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketBindToAddressEnd;
- }
- //
- // Take a reference on the path point before closing the named handle.
- //
- ASSERT(UnixSocket->PathPoint.PathEntry == NULL);
- IO_COPY_PATH_POINT(&(UnixSocket->PathPoint), &PathPoint);
- IO_INITIALIZE_PATH_POINT(&PathPoint);
- //
- // Set the state of the socket to be bound.
- //
- UnixSocket->Name = PathCopy;
- UnixSocket->NameSize = PathSize;
- PathCopy = NULL;
- UnixSocket->State = UnixSocketStateBound;
- Status = STATUS_SUCCESS;
- UnixSocketBindToAddressEnd:
- KeReleaseQueuedLock(UnixSocket->Lock);
- if ((PathCopy != NULL) && (PathCopy != Path)) {
- MmFreePagedPool(PathCopy);
- }
- if (PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
- }
- return Status;
- }
- KSTATUS
- IopUnixSocketListen (
- PSOCKET Socket,
- ULONG BacklogCount
- )
- /*++
- Routine Description:
- This routine adds a bound socket to the list of listening sockets,
- officially allowing sockets to attempt to connect to it.
- Arguments:
- Socket - Supplies a pointer to the socket to mark as listening.
- BacklogCount - Supplies the number of attempted connections that can be
- queued before additional connections are refused.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- ASSERT(Socket->Domain == NetDomainLocal);
- UnixSocket = (PUNIX_SOCKET)Socket;
- KeAcquireQueuedLock(UnixSocket->Lock);
- //
- // Only connection-oriented sockets can listen.
- //
- if ((Socket->Type != NetSocketStream) &&
- (Socket->Type != NetSocketSequencedPacket)) {
- Status = STATUS_NOT_SUPPORTED;
- goto UnixSocketListenEnd;
- }
- //
- // The socket had better have just been bound and that's it. Allow folks
- // that have already called listen to call listen again with a new backlog
- // parameter.
- //
- if ((UnixSocket->State != UnixSocketStateBound) &&
- (UnixSocket->State != UnixSocketStateListening)) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketListenEnd;
- }
- UnixSocket->MaxBacklog = BacklogCount;
- if (UnixSocket->State != UnixSocketStateListening) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_IN, FALSE);
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_OUT, TRUE);
- UnixSocket->State = UnixSocketStateListening;
- }
- IopUnixSocketInitializeCredentials(UnixSocket);
- Status = STATUS_SUCCESS;
- UnixSocketListenEnd:
- KeReleaseQueuedLock(UnixSocket->Lock);
- return Status;
- }
- KSTATUS
- IopUnixSocketAccept (
- PSOCKET Socket,
- PIO_HANDLE *NewConnectionSocket,
- PNETWORK_ADDRESS RemoteAddress,
- PSTR *RemotePath,
- PUINTN RemotePathSize
- )
- /*++
- Routine Description:
- This routine accepts an incoming connection on a listening connection-based
- socket.
- Arguments:
- Socket - Supplies a pointer to the socket to accept a connection from.
- NewConnectionSocket - Supplies a pointer where a new socket will be
- returned that represents the accepted connection with the remote
- host.
- RemoteAddress - Supplies a pointer where the address of the connected
- remote host will be returned.
- RemotePath - Supplies a pointer where a string containing the remote path
- will be returned on success. The caller does not own this string, it is
- connected with the new socket coming out.
- RemotePathSize - Supplies a pointer where the size of the remote path in
- bytes will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- BOOL LockHeld;
- PIO_HANDLE NewSocketHandle;
- PUNIX_SOCKET NewUnixSocket;
- ULONG ReturnedEvents;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- ASSERT(Socket->Domain == NetDomainLocal);
- LockHeld = FALSE;
- NewSocketHandle = NULL;
- UnixSocket = (PUNIX_SOCKET)Socket;
- //
- // Only connection-oriented sockets can accept.
- //
- if ((Socket->Type != NetSocketStream) &&
- (Socket->Type != NetSocketSequencedPacket)) {
- Status = STATUS_NOT_SUPPORTED;
- goto UnixSocketAcceptEnd;
- }
- //
- // Wait for a new connection to come in.
- //
- while (TRUE) {
- //
- // Race to acquire the lock and be the one to win the new connection.
- //
- KeAcquireQueuedLock(UnixSocket->Lock);
- LockHeld = TRUE;
- //
- // The socket had better be listening.
- //
- if ((UnixSocket->State != UnixSocketStateListening) &&
- (UnixSocket->State != UnixSocketStateShutdown)) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketAcceptEnd;
- }
- //
- // If there's a connection ready, break out with the lock held and get
- // it.
- //
- if (UnixSocket->CurrentBacklog != 0) {
- break;
- }
- //
- // If the socket is shut down, don't wait.
- //
- if (UnixSocket->State != UnixSocketStateListening) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketAcceptEnd;
- }
- //
- // Whoever did win the new connection better have reset the event.
- //
- ASSERT((Socket->IoState->Events & POLL_EVENT_IN) == 0);
- KeReleaseQueuedLock(UnixSocket->Lock);
- Status = IoWaitForIoObjectState(Socket->IoState,
- POLL_EVENT_IN,
- TRUE,
- WAIT_TIME_INDEFINITE,
- &ReturnedEvents);
- if (!KSUCCESS(Status)) {
- goto UnixSocketAcceptEnd;
- }
- ASSERT((ReturnedEvents & POLL_EVENT_IN) != 0);
- }
- //
- // Grab the new server side socket.
- //
- ASSERT(LIST_EMPTY(&(UnixSocket->ConnectionListEntry)) == FALSE);
- NewUnixSocket = LIST_VALUE(UnixSocket->ConnectionListEntry.Next,
- UNIX_SOCKET,
- ConnectionListEntry);
- LIST_REMOVE(&(NewUnixSocket->ConnectionListEntry));
- Status = STATUS_SUCCESS;
- ASSERT(NewUnixSocket->State == UnixSocketStateConnected);
- ASSERT(UnixSocket->CurrentBacklog != 0);
- UnixSocket->CurrentBacklog -= 1;
- if (UnixSocket->CurrentBacklog < UnixSocket->MaxBacklog) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_OUT, TRUE);
- }
- //
- // Unsignal the server if that was the last connection.
- //
- if (LIST_EMPTY(&(UnixSocket->ConnectionListEntry)) != FALSE) {
- IoSetIoObjectState(UnixSocket->KernelSocket.IoState,
- POLL_EVENT_IN,
- FALSE);
- }
- RtlZeroMemory(RemoteAddress, sizeof(NETWORK_ADDRESS));
- RemoteAddress->Domain = NetDomainLocal;
- *RemotePath = NewUnixSocket->Remote->Name;
- *RemotePathSize = NewUnixSocket->Remote->NameSize;
- NewSocketHandle = NewUnixSocket->KernelSocket.IoHandle;
- UnixSocketAcceptEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(UnixSocket->Lock);
- }
- if (!KSUCCESS(Status)) {
- NewSocketHandle = NULL;
- }
- *NewConnectionSocket = NewSocketHandle;
- return Status;
- }
- KSTATUS
- IopUnixSocketConnect (
- BOOL FromKernelMode,
- PSOCKET Socket,
- PNETWORK_ADDRESS Address,
- PSTR RemotePath,
- UINTN RemotePathSize
- )
- /*++
- Routine Description:
- This routine attempts to make an outgoing connection to a server.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the request is coming
- from kernel mode (TRUE) or user mode (FALSE).
- Socket - Supplies a pointer to the socket to use for the connection.
- Address - Supplies a pointer to the address to connect to.
- RemotePath - Supplies a pointer to the string containing the path to
- connect to.
- RemotePathSize - Supplies the size fo the remote path string in bytes,
- including the null terminator.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- PSOCKET NewSocket;
- PIO_HANDLE NewSocketHandle;
- PUNIX_SOCKET NewUnixSocket;
- ULONG OpenFlags;
- PATH_POINT PathPoint;
- ULONG ReturnedEvents;
- BOOL ServerLockHeld;
- PSOCKET ServerSocket;
- PUNIX_SOCKET ServerUnixSocket;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- PSTR WalkedPath;
- ULONG WalkedPathSize;
- NewSocketHandle = NULL;
- IO_INITIALIZE_PATH_POINT(&PathPoint);
- ServerLockHeld = FALSE;
- ServerUnixSocket = NULL;
- UnixSocket = (PUNIX_SOCKET)Socket;
- KeAcquireQueuedLock(UnixSocket->Lock);
- if (Address->Domain != NetDomainLocal) {
- Status = STATUS_UNEXPECTED_TYPE;
- goto UnixSocketConnectEnd;
- }
- if ((Socket->Type != NetSocketStream) &&
- (Socket->Type != NetSocketSequencedPacket) &&
- (Socket->Type != NetSocketDatagram)) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketConnectEnd;
- }
- if (RemotePathSize == 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketConnectEnd;
- }
- if (UnixSocket->State == UnixSocketStateConnected) {
- Status = STATUS_CONNECTION_EXISTS;
- goto UnixSocketConnectEnd;
- }
- if ((UnixSocket->State != UnixSocketStateInitialized) &&
- (UnixSocket->State != UnixSocketStateBound)) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketConnectEnd;
- }
- //
- // Attempt to open a handle to the socket.
- //
- ASSERT((PVOID)RemotePath >= KERNEL_VA_START);
- WalkedPath = RemotePath;
- WalkedPathSize = RemotePathSize;
- Status = IopPathWalk(FromKernelMode,
- NULL,
- &WalkedPath,
- &WalkedPathSize,
- 0,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &PathPoint);
- if (!KSUCCESS(Status)) {
- goto UnixSocketConnectEnd;
- }
- Status = IopCheckPermissions(FromKernelMode,
- &PathPoint,
- IO_ACCESS_READ | IO_ACCESS_WRITE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketConnectEnd;
- }
- //
- // Get the socket from the file object.
- //
- FileObject = PathPoint.PathEntry->FileObject;
- if (FileObject->Properties.Type != IoObjectSocket) {
- Status = STATUS_NOT_A_SOCKET;
- goto UnixSocketConnectEnd;
- }
- ServerSocket = FileObject->SpecialIo;
- ASSERT(ServerSocket->Domain == NetDomainLocal);
- ServerUnixSocket = (PUNIX_SOCKET)ServerSocket;
- //
- // Fail if the types disagree.
- //
- if (ServerSocket->Type != Socket->Type) {
- Status = STATUS_INVALID_ADDRESS;
- goto UnixSocketConnectEnd;
- }
- //
- // For datagram sockets, just set it as the remote and go on.
- //
- if (Socket->Type == NetSocketDatagram) {
- UnixSocket->Remote = ServerUnixSocket;
- //
- // For connection-based sockets, really connect the two.
- //
- } else {
- //
- // Stream sockets are not allowed to be both the server and the client.
- // Fail if it's the same socket. The socket's state should not be
- // listening, but special case it here by comparing the sockets to
- // prevent the attempt to reacquire the lock.
- //
- if (ServerSocket == Socket) {
- ASSERT(ServerUnixSocket->State != UnixSocketStateListening);
- Status = STATUS_CONNECTION_CLOSED;
- goto UnixSocketConnectEnd;
- }
- //
- // Loop until the lock is held and there's space for a new connection.
- //
- OpenFlags = IoGetIoHandleOpenFlags(Socket->IoHandle);
- while (TRUE) {
- KeAcquireQueuedLock(ServerUnixSocket->Lock);
- ServerLockHeld = TRUE;
- if (ServerUnixSocket->State != UnixSocketStateListening) {
- Status = STATUS_CONNECTION_CLOSED;
- goto UnixSocketConnectEnd;
- }
- if (ServerUnixSocket->CurrentBacklog >=
- ServerUnixSocket->MaxBacklog) {
- ASSERT((ServerSocket->IoState->Events & POLL_EVENT_OUT) == 0);
- KeReleaseQueuedLock(ServerUnixSocket->Lock);
- ServerLockHeld = FALSE;
- //
- // If it was opened non-blocking, then return immediately.
- //
- if ((OpenFlags & OPEN_FLAG_NON_BLOCKING) != 0) {
- Status = STATUS_OPERATION_WOULD_BLOCK;
- goto UnixSocketConnectEnd;
- }
- Status = IoWaitForIoObjectState(ServerSocket->IoState,
- POLL_EVENT_OUT,
- TRUE,
- WAIT_TIME_INDEFINITE,
- &ReturnedEvents);
- if (!KSUCCESS(Status)) {
- goto UnixSocketConnectEnd;
- }
- //
- // The lock is held and there's space.
- //
- } else {
- break;
- }
- }
- //
- // The server's lock is held. Create a new socket on the server side to
- // represent this connection. Creating the server's socket in connect
- // allows the connection to be fully established when this routine
- // returns, even if the accept call hasn't happened yet. This is in
- // line with behavior of other systems.
- //
- Status = IoSocketCreate(Socket->Domain,
- Socket->Type,
- Socket->Protocol,
- 0,
- &NewSocketHandle);
- if (!KSUCCESS(Status)) {
- goto UnixSocketConnectEnd;
- }
- Status = IoGetSocketFromHandle(NewSocketHandle, &NewSocket);
- if (!KSUCCESS(Status)) {
- goto UnixSocketConnectEnd;
- }
- ASSERT(NewSocket->Domain == NetDomainLocal);
- NewUnixSocket = (PUNIX_SOCKET)NewSocket;
- //
- // Copy the path.
- //
- if (ServerUnixSocket->Name != NULL) {
- NewUnixSocket->Name = MmAllocatePagedPool(
- ServerUnixSocket->NameSize,
- UNIX_SOCKET_ALLOCATION_TAG);
- if (NewUnixSocket->Name == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UnixSocketConnectEnd;
- }
- NewUnixSocket->NameSize = ServerUnixSocket->NameSize;
- RtlCopyMemory(NewUnixSocket->Name,
- ServerUnixSocket->Name,
- NewUnixSocket->NameSize);
- }
- ASSERT(ServerUnixSocket->Credentials.ProcessId != -1);
- RtlCopyMemory(&(NewUnixSocket->Credentials),
- &(ServerUnixSocket->Credentials),
- sizeof(UNIX_SOCKET_CREDENTIALS));
- //
- // Wire the two sockets together in a connection.
- //
- ASSERT(ServerUnixSocket->CurrentBacklog < ServerUnixSocket->MaxBacklog);
- IoSetIoObjectState(NewUnixSocket->KernelSocket.IoState,
- POLL_EVENT_IN | POLL_EVENT_OUT,
- TRUE);
- UnixSocket->Remote = NewUnixSocket;
- IoSocketAddReference(&(NewUnixSocket->KernelSocket));
- NewUnixSocket->Remote = UnixSocket;
- IoSocketAddReference(&(UnixSocket->KernelSocket));
- UnixSocket->State = UnixSocketStateConnected;
- NewUnixSocket->State = UnixSocketStateConnected;
- INSERT_BEFORE(&(NewUnixSocket->ConnectionListEntry),
- &(ServerUnixSocket->ConnectionListEntry));
- if (ServerUnixSocket->CurrentBacklog == 0) {
- IoSetIoObjectState(ServerSocket->IoState, POLL_EVENT_IN, TRUE);
- }
- ServerUnixSocket->CurrentBacklog += 1;
- KeReleaseQueuedLock(ServerUnixSocket->Lock);
- ServerLockHeld = FALSE;
- }
- IopUnixSocketInitializeCredentials(UnixSocket);
- Status = STATUS_SUCCESS;
- UnixSocketConnectEnd:
- KeReleaseQueuedLock(UnixSocket->Lock);
- if (PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
- }
- if (ServerLockHeld != FALSE) {
- KeReleaseQueuedLock(ServerUnixSocket->Lock);
- }
- return Status;
- }
- KSTATUS
- IopUnixSocketSendData (
- BOOL FromKernelMode,
- PSOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- )
- /*++
- Routine Description:
- This routine sends the given data buffer through the local socket.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the request is coming
- from kernel mode or user mode. This value affects the root path node
- to traverse for local domain sockets.
- Socket - Supplies a pointer to the socket to send the data to.
- Parameters - Supplies a pointer to the I/O parameters.
- IoBuffer - Supplies a pointer to the I/O buffer containing the data to
- send.
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesCompleted;
- PNETWORK_ADDRESS Destination;
- NETWORK_ADDRESS DestinationLocal;
- PFILE_OBJECT FileObject;
- ULONG OpenFlags;
- PUNIX_SOCKET_PACKET Packet;
- UINTN PacketSize;
- PATH_POINT PathPoint;
- PKPROCESS Process;
- PSTR RemoteCopy;
- PSTR RemotePath;
- PSOCKET RemoteSocket;
- PUNIX_SOCKET RemoteUnixSocket;
- ULONG ReturnedEvents;
- UINTN Size;
- KSTATUS Status;
- PKTHREAD Thread;
- PUNIX_SOCKET UnixSocket;
- BOOL UnixSocketLockHeld;
- PSTR WalkedPath;
- UINTN WalkedPathSize;
- BytesCompleted = 0;
- Packet = NULL;
- IO_INITIALIZE_PATH_POINT(&PathPoint);
- RemoteCopy = NULL;
- UnixSocket = (PUNIX_SOCKET)Socket;
- KeAcquireQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = TRUE;
- //
- // Make sure the socket is properly connected (or as connected as it needs
- // to be).
- //
- Status = IopUnixSocketEnsureConnected(UnixSocket, TRUE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- //
- // Get or open the remote socket being sent to.
- //
- RemoteUnixSocket = UnixSocket->Remote;
- Destination = Parameters->NetworkAddress;
- if ((Destination != NULL) && (FromKernelMode == FALSE)) {
- Status = MmCopyFromUserMode(&DestinationLocal,
- Destination,
- sizeof(NETWORK_ADDRESS));
- Destination = &DestinationLocal;
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- }
- if ((Destination != NULL) &&
- (Destination->Domain != NetDomainInvalid)) {
- if (UnixSocket->KernelSocket.Type != NetSocketDatagram) {
- Status = STATUS_NOT_SUPPORTED;
- goto UnixSocketSendDataEnd;
- }
- if (Destination->Domain != NetDomainLocal) {
- Status = STATUS_UNEXPECTED_TYPE;
- goto UnixSocketSendDataEnd;
- }
- if (Parameters->RemotePathSize == 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketSendDataEnd;
- }
- RemotePath = Parameters->RemotePath;
- if (FromKernelMode == FALSE) {
- Status = MmCreateCopyOfUserModeString(RemotePath,
- Parameters->RemotePathSize,
- UNIX_SOCKET_ALLOCATION_TAG,
- &RemoteCopy);
- RemotePath = RemoteCopy;
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- }
- ASSERT((PVOID)RemotePath >= KERNEL_VA_START);
- WalkedPath = RemotePath;
- WalkedPathSize = Parameters->RemotePathSize;
- Status = IopPathWalk(FromKernelMode,
- NULL,
- &WalkedPath,
- &WalkedPathSize,
- 0,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &PathPoint);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- Status = IopCheckPermissions(FromKernelMode,
- &PathPoint,
- IO_ACCESS_READ | IO_ACCESS_WRITE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- //
- // Get the socket from the file object.
- //
- FileObject = PathPoint.PathEntry->FileObject;
- if (FileObject->Properties.Type != IoObjectSocket) {
- return STATUS_NOT_A_SOCKET;
- }
- ASSERT((UINTN)(FileObject->Properties.DeviceId) ==
- OBJECT_MANAGER_DEVICE_ID);
- RemoteSocket = (PSOCKET)(UINTN)(FileObject->Properties.FileId);
- ASSERT(RemoteSocket->Domain == NetDomainLocal);
- RemoteUnixSocket = (PUNIX_SOCKET)RemoteSocket;
- }
- if (RemoteUnixSocket == NULL) {
- Status = STATUS_NOT_CONNECTED;
- goto UnixSocketSendDataEnd;
- }
- OpenFlags = IoGetIoHandleOpenFlags(Socket->IoHandle);
- //
- // Loop while there's data to send.
- //
- Size = Parameters->Size;
- while (Size != 0) {
- if (UnixSocketLockHeld == FALSE) {
- KeAcquireQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = TRUE;
- }
- //
- // Make sure a close didn't sneak in while the lock was not held.
- //
- Status = IopUnixSocketEnsureConnected(UnixSocket, TRUE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- //
- // For types where the message boundaries matter, the size must fit in
- // a single packet.
- //
- if ((Socket->Type == NetSocketDatagram) ||
- (Socket->Type == NetSocketSequencedPacket)) {
- if (Size > UnixSocket->SendListMax) {
- Status = STATUS_MESSAGE_TOO_LONG;
- goto UnixSocketSendDataEnd;
- }
- }
- if (UnixSocket->SendListSize >= UnixSocket->SendListMax) {
- PacketSize = 0;
- } else {
- PacketSize = UnixSocket->SendListMax - UnixSocket->SendListSize;
- }
- if (PacketSize > Size) {
- PacketSize = Size;
- }
- //
- // If the whole packet needs to be sent in one go, block to wait for
- // more space to free up, and try again.
- //
- if ((Socket->Type == NetSocketDatagram) ||
- (Socket->Type == NetSocketSequencedPacket)) {
- if (Size > PacketSize) {
- PacketSize = 0;
- }
- //
- // Streams can send multiple packets at a time.
- //
- } else {
- ASSERT(Socket->Type == NetSocketStream);
- }
- //
- // Create the packet.
- //
- Packet = NULL;
- if (PacketSize != 0) {
- Packet = NULL;
- Status = IopUnixSocketCreatePacket(UnixSocket,
- IoBuffer,
- BytesCompleted,
- PacketSize,
- &Packet);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- //
- // Charge the socket for the data while the lock is still held.
- //
- UnixSocket->SendListSize += PacketSize;
- if (UnixSocket->SendListSize >= UnixSocket->SendListMax) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_OUT, FALSE);
- }
- if ((Parameters->ControlData != NULL) &&
- (Parameters->ControlDataSize != 0)) {
- Status = IopUnixSocketSendControlData(
- FromKernelMode,
- UnixSocket,
- Packet,
- Parameters->ControlData,
- Parameters->ControlDataSize);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- }
- //
- // Send the credentials if either side has that option set.
- //
- if ((Packet->Credentials.ProcessId == -1) &&
- (((UnixSocket->Flags | RemoteUnixSocket->Flags) &
- UNIX_SOCKET_FLAG_SEND_CREDENTIALS) != 0)) {
- Thread = KeGetCurrentThread();
- Process = Thread->OwningProcess;
- Packet->Credentials.ProcessId = Process->Identifiers.ProcessId;
- Packet->Credentials.UserId = Thread->Identity.RealUserId;
- Packet->Credentials.GroupId = Thread->Identity.RealGroupId;
- }
- //
- // The packet doesn't fit, so block until data is flushed out.
- //
- } else {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_OUT, FALSE);
- }
- KeReleaseQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = FALSE;
- //
- // If no packet was created, wait for some space to open up.
- //
- if (Packet == NULL) {
- if ((OpenFlags & OPEN_FLAG_NON_BLOCKING) != 0) {
- Status = STATUS_OPERATION_WOULD_BLOCK;
- goto UnixSocketSendDataEnd;
- }
- Status = IoWaitForIoObjectState(Socket->IoState,
- POLL_EVENT_OUT,
- TRUE,
- Parameters->TimeoutInMilliseconds,
- &ReturnedEvents);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendDataEnd;
- }
- //
- // Try again to send some data.
- //
- continue;
- }
- //
- // Both locks should not be held at once because it could create lock
- // ordering issues.
- //
- ASSERT(UnixSocketLockHeld == FALSE);
- KeAcquireQueuedLock(RemoteUnixSocket->Lock);
- if (RemoteUnixSocket->KernelSocket.Type != Socket->Type) {
- KeReleaseQueuedLock(RemoteUnixSocket->Lock);
- Status = STATUS_UNEXPECTED_TYPE;
- goto UnixSocketSendDataEnd;
- }
- //
- // Make sure the server is connected.
- //
- Status = IopUnixSocketEnsureConnected(RemoteUnixSocket, FALSE);
- if (!KSUCCESS(Status)) {
- Status = STATUS_BROKEN_PIPE;
- KeReleaseQueuedLock(RemoteUnixSocket->Lock);
- goto UnixSocketSendDataEnd;
- }
- INSERT_BEFORE(&(Packet->ListEntry), &(RemoteUnixSocket->ReceiveList));
- //
- // If this is the only item on the list, signal the remote socket.
- //
- if (Packet->ListEntry.Previous == &(RemoteUnixSocket->ReceiveList)) {
- IoSetIoObjectState(RemoteUnixSocket->KernelSocket.IoState,
- POLL_EVENT_IN,
- TRUE);
- }
- KeReleaseQueuedLock(RemoteUnixSocket->Lock);
- Packet = NULL;
- BytesCompleted += PacketSize;
- Size -= PacketSize;
- }
- UnixSocketSendDataEnd:
- if (RemoteCopy != NULL) {
- MmFreePagedPool(RemoteCopy);
- }
- if (!KSUCCESS(Status)) {
- //
- // Roll back the charge to the socket if the packet is still around.
- //
- if (Packet != NULL) {
- if (UnixSocketLockHeld == FALSE) {
- KeAcquireQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = TRUE;
- }
- ASSERT(UnixSocket->SendListSize >= Packet->Length);
- UnixSocket->SendListSize -= Packet->Length;
- if (UnixSocket->SendListSize < UnixSocket->SendListMax) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_OUT, TRUE);
- }
- IopUnixSocketDestroyPacket(Packet);
- }
- }
- if (UnixSocketLockHeld != FALSE) {
- KeReleaseQueuedLock(UnixSocket->Lock);
- }
- if (PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
- }
- Parameters->Size = BytesCompleted;
- return Status;
- }
- KSTATUS
- IopUnixSocketReceiveData (
- BOOL FromKernelMode,
- PSOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- )
- /*++
- Routine Description:
- This routine is called by the user to receive data from the socket.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the request is coming
- from kernel mode or user mode. This value affects the root path node
- to traverse for local domain sockets.
- Socket - Supplies a pointer to the socket to receive data from.
- Parameters - Supplies a pointer to the socket I/O parameters.
- IoBuffer - Supplies a pointer to the I/O buffer where the received data
- will be returned.
- Return Value:
- Status code.
- --*/
- {
- UINTN ByteCount;
- UINTN BytesReceived;
- PUNIX_SOCKET FirstSender;
- ULONG OpenFlags;
- PUNIX_SOCKET_PACKET Packet;
- PUNIX_SOCKET Remote;
- NETWORK_ADDRESS RemoteAddressLocal;
- ULONG ReturnedEvents;
- UINTN SenderCopySize;
- UINTN Size;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- BOOL UnixSocketLockHeld;
- BytesReceived = 0;
- FirstSender = NULL;
- Size = Parameters->Size;
- UnixSocket = (PUNIX_SOCKET)Socket;
- UnixSocketLockHeld = FALSE;
- ASSERT(Socket->Domain == NetDomainLocal);
- //
- // Loop reading stuff.
- //
- OpenFlags = IoGetIoHandleOpenFlags(Socket->IoHandle);
- while (Size != 0) {
- if (UnixSocketLockHeld == FALSE) {
- KeAcquireQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = TRUE;
- }
- Status = IopUnixSocketEnsureConnected(UnixSocket, FALSE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- //
- // If the list is empty, wait and try again.
- //
- if (LIST_EMPTY(&(UnixSocket->ReceiveList)) != FALSE) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_IN, FALSE);
- //
- // If something was retrieved already, just use that.
- //
- if (BytesReceived != 0) {
- break;
- }
- //
- // If this is a connection oriented socket and the remote is shut
- // down for writing, end now.
- //
- if ((Socket->Type == NetSocketStream) ||
- (Socket->Type == NetSocketSequencedPacket)) {
- Remote = UnixSocket->Remote;
- if ((Remote != NULL) &&
- (Remote->State != UnixSocketStateConnected) &&
- (Remote->State != UnixSocketStateShutdownRead)) {
- Status = STATUS_END_OF_FILE;
- goto UnixSocketReceiveDataEnd;
- }
- }
- if ((OpenFlags & OPEN_FLAG_NON_BLOCKING) != 0) {
- Status = STATUS_OPERATION_WOULD_BLOCK;
- goto UnixSocketReceiveDataEnd;
- }
- KeReleaseQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = FALSE;
- Status = IoWaitForIoObjectState(Socket->IoState,
- POLL_EVENT_IN,
- TRUE,
- Parameters->TimeoutInMilliseconds,
- &ReturnedEvents);
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- continue;
- //
- // Grab stuff off the list.
- //
- } else {
- Packet = LIST_VALUE(UnixSocket->ReceiveList.Next,
- UNIX_SOCKET_PACKET,
- ListEntry);
- //
- // Don't cross boundaries of different senders or packets with
- // control data.
- //
- if (FirstSender != NULL) {
- if ((Packet->Sender != FirstSender) ||
- (Packet->Credentials.ProcessId != -1) ||
- (Packet->Credentials.UserId != -1) ||
- (Packet->Credentials.GroupId != -1) ||
- (Packet->HandleCount != 0)) {
- break;
- }
- }
- FirstSender = Packet->Sender;
- ByteCount = Packet->Length - Packet->Offset;
- if (ByteCount > Size) {
- ByteCount = Size;
- }
- Status = MmCopyIoBufferData(IoBuffer,
- Packet->Data + Packet->Offset,
- BytesReceived,
- ByteCount,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- Packet->Offset += ByteCount;
- BytesReceived += ByteCount;
- Size -= ByteCount;
- //
- // Copy the ancillary data as well.
- //
- Status = IopUnixSocketReceiveControlData(FromKernelMode,
- UnixSocket,
- Packet,
- Parameters);
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- //
- // Return the remote path if requested.
- //
- if ((Parameters->RemotePath != NULL) &&
- (Parameters->RemotePathSize != 0)) {
- SenderCopySize = Packet->Sender->NameSize;
- if (SenderCopySize > Parameters->RemotePathSize) {
- SenderCopySize = Parameters->RemotePathSize;
- }
- Parameters->RemotePathSize = Packet->Sender->NameSize;
- if (SenderCopySize != 0) {
- if (FromKernelMode != FALSE) {
- RtlCopyMemory(Parameters->RemotePath,
- Packet->Sender->Name,
- SenderCopySize);
- } else {
- Status = MmCopyToUserMode(Parameters->RemotePath,
- Packet->Sender->Name,
- SenderCopySize);
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- }
- }
- }
- //
- // Copy the network address portion of the sender address as well.
- //
- if (Parameters->NetworkAddress != NULL) {
- if (FromKernelMode != FALSE) {
- Parameters->NetworkAddress->Domain = NetDomainLocal;
- } else {
- RtlZeroMemory(&RemoteAddressLocal, sizeof(NETWORK_ADDRESS));
- RemoteAddressLocal.Domain = NetDomainLocal;
- Status = MmCopyToUserMode(Parameters->NetworkAddress,
- &RemoteAddressLocal,
- sizeof(NETWORK_ADDRESS));
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveDataEnd;
- }
- }
- }
- //
- // If the packet was completely consumed or this is datagram mode,
- // destroy the packet.
- //
- if ((Packet->Offset >= Packet->Length) ||
- (Socket->Type == NetSocketDatagram)) {
- LIST_REMOVE(&(Packet->ListEntry));
- if (LIST_EMPTY(&(UnixSocket->ReceiveList)) != FALSE) {
- IoSetIoObjectState(Socket->IoState, POLL_EVENT_IN, FALSE);
- }
- //
- // Release the sender if needed. Release the lock first so that
- // both locks are not held at once, which could cause lock
- // ordering problems.
- //
- KeReleaseQueuedLock(UnixSocket->Lock);
- UnixSocketLockHeld = FALSE;
- KeAcquireQueuedLock(Packet->Sender->Lock);
- ASSERT(Packet->Sender->SendListSize >= Packet->Length);
- IoSetIoObjectState(Packet->Sender->KernelSocket.IoState,
- POLL_EVENT_OUT,
- TRUE);
- Packet->Sender->SendListSize -= Packet->Length;
- KeReleaseQueuedLock(Packet->Sender->Lock);
- //
- // Destroy the sender's packet.
- //
- IopUnixSocketDestroyPacket(Packet);
- }
- //
- // For datagram or sequenced packet sockets, only return one packet
- // at a time.
- //
- if ((Socket->Type == NetSocketDatagram) ||
- (Socket->Type == NetSocketSequencedPacket)) {
- break;
- }
- }
- }
- Status = STATUS_SUCCESS;
- UnixSocketReceiveDataEnd:
- if (UnixSocketLockHeld != FALSE) {
- KeReleaseQueuedLock(UnixSocket->Lock);
- }
- if ((Status == STATUS_END_OF_FILE) && (BytesReceived != 0)) {
- Status = STATUS_SUCCESS;
- }
- Parameters->Size = BytesReceived;
- return Status;
- }
- KSTATUS
- IopUnixSocketGetSetSocketInformation (
- PSOCKET Socket,
- SOCKET_INFORMATION_TYPE InformationType,
- UINTN Option,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets properties of the given socket.
- Arguments:
- Socket - Supplies a pointer to the socket to get or set information for.
- InformationType - Supplies the socket information type category to which
- specified option belongs.
- Option - Supplies the option to get or set, which is specific to the
- information type. The type of this value is generally
- SOCKET_<information_type>_OPTION.
- Data - Supplies a pointer to the data buffer where the data is either
- returned for a get operation or given for a set operation.
- DataSize - Supplies a pointer that on input constains the size of the data
- buffer. On output, this contains the required size of the data buffer.
- Set - Supplies a boolean indicating if this is a get operation (FALSE) or
- a set operation (TRUE).
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the information type is incorrect.
- STATUS_BUFFER_TOO_SMALL if the data buffer is too small to receive the
- requested option.
- STATUS_NOT_SUPPORTED_BY_PROTOCOL if the socket option is not supported by
- the socket.
- --*/
- {
- NETWORK_ADDRESS Address;
- SOCKET_BASIC_OPTION BasicOption;
- UINTN CopySize;
- ULONG PassCredentials;
- UINTN RemainingSize;
- UINTN RequiredSize;
- UINTN SendListMax;
- PVOID Source;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- UnixSocket = (PUNIX_SOCKET)Socket;
- ASSERT(Socket->Domain == NetDomainLocal);
- Source = NULL;
- RequiredSize = 0;
- Status = STATUS_SUCCESS;
- switch (InformationType) {
- case SocketInformationBasic:
- BasicOption = (SOCKET_BASIC_OPTION)Option;
- switch (BasicOption) {
- case SocketBasicOptionType:
- if (Set != FALSE) {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- break;
- }
- Source = &(Socket->Type);
- RequiredSize = sizeof(NET_SOCKET_TYPE);
- break;
- case SocketBasicOptionDomain:
- if (Set != FALSE) {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- break;
- }
- Source = &(Socket->Domain);
- RequiredSize = sizeof(NET_DOMAIN_TYPE);
- break;
- //
- // Switch to the remote socket and fall through.
- //
- case SocketBasicOptionRemoteAddress:
- UnixSocket = UnixSocket->Remote;
- case SocketBasicOptionLocalAddress:
- if (Set != FALSE) {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- break;
- }
- if (UnixSocket == NULL) {
- Status = STATUS_NOT_CONNECTED;
- break;
- }
- RtlZeroMemory(&Address, sizeof(NETWORK_ADDRESS));
- Address.Domain = NetDomainLocal;
- KeAcquireQueuedLock(UnixSocket->Lock);
- RequiredSize = sizeof(NETWORK_ADDRESS) + UnixSocket->NameSize;
- if (*DataSize > RequiredSize) {
- *DataSize = RequiredSize;
- }
- RemainingSize = *DataSize;
- CopySize = RemainingSize;
- if (CopySize > sizeof(NETWORK_ADDRESS)) {
- CopySize = sizeof(NETWORK_ADDRESS);
- }
- //
- // The lock must be held while the name is copied, so this cannot
- // be done below.
- //
- RtlCopyMemory(Data, &Address, CopySize);
- RemainingSize -= CopySize;
- if ((RemainingSize != 0) && (UnixSocket->NameSize != 0)) {
- ASSERT(RemainingSize <= UnixSocket->NameSize);
- RtlCopyMemory(Data + CopySize, UnixSocket->Name, RemainingSize);
- }
- KeReleaseQueuedLock(UnixSocket->Lock);
- break;
- case SocketBasicOptionSendBufferSize:
- if ((Set != FALSE) && (*DataSize < sizeof(ULONG))) {
- *DataSize = sizeof(ULONG);
- Status = STATUS_BUFFER_TOO_SMALL;
- break;
- }
- RequiredSize = sizeof(ULONG);
- if (Set != FALSE) {
- SendListMax = *((PULONG)Data);
- if (SendListMax > SOCKET_OPTION_MAX_ULONG) {
- SendListMax = SOCKET_OPTION_MAX_ULONG;
- }
- //
- // TODO: Are there limits to Unix socket buffer sizes?
- //
- KeAcquireQueuedLock(UnixSocket->Lock);
- UnixSocket->SendListMax = SendListMax;
- KeReleaseQueuedLock(UnixSocket->Lock);
- } else {
- Source = &SendListMax;
- SendListMax = UnixSocket->SendListMax;
- }
- break;
- case SocketBasicOptionPassCredentials:
- if ((Set != FALSE) && (*DataSize < sizeof(ULONG))) {
- *DataSize = sizeof(ULONG);
- Status = STATUS_BUFFER_TOO_SMALL;
- break;
- }
- RequiredSize = sizeof(ULONG);
- KeAcquireQueuedLock(UnixSocket->Lock);
- if (Set != FALSE) {
- UnixSocket->Flags &= ~UNIX_SOCKET_FLAG_SEND_CREDENTIALS;
- if (*((PULONG)Data) != FALSE) {
- UnixSocket->Flags |= UNIX_SOCKET_FLAG_SEND_CREDENTIALS;
- }
- } else {
- Source = &PassCredentials;
- PassCredentials = FALSE;
- if ((UnixSocket->Flags &
- UNIX_SOCKET_FLAG_SEND_CREDENTIALS) != 0) {
- PassCredentials = TRUE;
- }
- }
- KeReleaseQueuedLock(UnixSocket->Lock);
- break;
- case SocketBasicOptionPeerCredentials:
- if (Set != FALSE) {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- break;
- }
- Source = &(UnixSocket->Remote->Credentials);
- RequiredSize = sizeof(UNIX_SOCKET_CREDENTIALS);
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- //
- // Complete the common information processing if this call succeeded.
- //
- if (KSUCCESS(Status)) {
- //
- // Truncate all copies for get requests down to the required size and
- // only return the required size on set requests.
- //
- if (*DataSize > RequiredSize) {
- *DataSize = RequiredSize;
- }
- //
- // For get requests, copy the gathered information to the supplied data
- // buffer.
- //
- if (Set == FALSE) {
- if (Source != NULL) {
- RtlCopyMemory(Data, Source, *DataSize);
- }
- //
- // If the copy truncated the data, report that the given buffer was
- // too small. The caller can choose to ignore this if the truncated
- // data is enough.
- //
- if (*DataSize < RequiredSize) {
- *DataSize = RequiredSize;
- Status = STATUS_BUFFER_TOO_SMALL;
- }
- }
- }
- return Status;
- }
- KSTATUS
- IopUnixSocketShutdown (
- PSOCKET Socket,
- ULONG ShutdownType
- )
- /*++
- Routine Description:
- This routine shuts down communication with a given socket.
- Arguments:
- Socket - Supplies a pointer to the socket.
- ShutdownType - Supplies the shutdown type to perform. See the
- SOCKET_SHUTDOWN_* definitions.
- Return Value:
- Status code.
- --*/
- {
- PUNIX_SOCKET RemoteToRelease;
- PUNIX_SOCKET RemoteToSignal;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- RemoteToRelease = NULL;
- RemoteToSignal = NULL;
- UnixSocket = (PUNIX_SOCKET)Socket;
- ASSERT(Socket->Domain == NetDomainLocal);
- KeAcquireQueuedLock(UnixSocket->Lock);
- if (UnixSocket->State == UnixSocketStateInitialized) {
- UnixSocket->State = UnixSocketStateShutdown;
- } else if ((UnixSocket->State >= UnixSocketStateBound) &&
- (UnixSocket->State < UnixSocketStateShutdown)) {
- if ((ShutdownType & SOCKET_SHUTDOWN_READ) != 0) {
- //
- // A listening socket can only shut down read, so treat it as a
- // full shutdown.
- //
- if (UnixSocket->State == UnixSocketStateListening) {
- UnixSocket->State = UnixSocketStateShutdown;
- //
- // It might already be shut down for writing.
- //
- } else if (UnixSocket->State == UnixSocketStateShutdownWrite) {
- UnixSocket->State = UnixSocketStateShutdown;
- } else if (UnixSocket->State != UnixSocketStateShutdown) {
- UnixSocket->State = UnixSocketStateShutdownRead;
- }
- IopUnixSocketFlushData(UnixSocket);
- }
- if ((ShutdownType & SOCKET_SHUTDOWN_WRITE) != 0) {
- //
- // Listening sockets can still accept new connections while
- // shutdown for write. Everything else closes.
- //
- if (UnixSocket->State == UnixSocketStateShutdownRead) {
- UnixSocket->State = UnixSocketStateShutdown;
- } else if (UnixSocket->State != UnixSocketStateListening) {
- if (UnixSocket->State != UnixSocketStateShutdown) {
- UnixSocket->State = UnixSocketStateShutdownWrite;
- }
- }
- //
- // If there's a remote connection for a connection-oriented socket,
- // signal it as no more data will be sent.
- //
- if ((Socket->Type == NetSocketStream) ||
- (Socket->Type == NetSocketSequencedPacket)) {
- RemoteToSignal = UnixSocket->Remote;
- }
- }
- //
- // Release the reference on the remote if the socket is completely
- // disconnected.
- //
- if (UnixSocket->State == UnixSocketStateShutdown) {
- RemoteToRelease = UnixSocket->Remote;
- UnixSocket->Remote = NULL;
- }
- }
- KeReleaseQueuedLock(UnixSocket->Lock);
- //
- // Signal the remote outside holding this socket lock to avoid lock
- // ordering problems.
- //
- if (RemoteToSignal != NULL) {
- KeAcquireQueuedLock(RemoteToSignal->Lock);
- IoSetIoObjectState(RemoteToSignal->KernelSocket.IoState,
- POLL_EVENT_IN,
- TRUE);
- KeReleaseQueuedLock(RemoteToSignal->Lock);
- }
- if (RemoteToRelease != NULL) {
- IoSocketReleaseReference(&(RemoteToRelease->KernelSocket));
- }
- Status = STATUS_SUCCESS;
- return Status;
- }
- KSTATUS
- IopUnixSocketClose (
- PSOCKET Socket
- )
- /*++
- Routine Description:
- This routine closes down a local socket.
- Arguments:
- Socket - Supplies a pointer to the socket.
- Return Value:
- Status code.
- --*/
- {
- PUNIX_SOCKET Connection;
- ULONG ShutdownFlags;
- KSTATUS Status;
- PUNIX_SOCKET UnixSocket;
- UnixSocket = (PUNIX_SOCKET)Socket;
- ASSERT(Socket->Domain == NetDomainLocal);
- //
- // Shut the socket down.
- //
- ShutdownFlags = SOCKET_SHUTDOWN_READ | SOCKET_SHUTDOWN_WRITE;
- Status = IopUnixSocketShutdown(Socket, ShutdownFlags);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- KeAcquireQueuedLock(UnixSocket->Lock);
- if (UnixSocket->State == UnixSocketStateClosed) {
- KeReleaseQueuedLock(UnixSocket->Lock);
- return STATUS_SUCCESS;
- }
- //
- // Destroy any incoming connections.
- //
- while (UnixSocket->CurrentBacklog != 0) {
- ASSERT(LIST_EMPTY(&(UnixSocket->ConnectionListEntry)) == FALSE);
- Connection = LIST_VALUE(UnixSocket->ConnectionListEntry.Next,
- UNIX_SOCKET,
- ConnectionListEntry);
- LIST_REMOVE(&(Connection->ConnectionListEntry));
- UnixSocket->CurrentBacklog -= 1;
- IoClose(UnixSocket->KernelSocket.IoHandle);
- }
- //
- // Release the reference on the path entry.
- //
- if (UnixSocket->PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&(UnixSocket->PathPoint));
- UnixSocket->PathPoint.PathEntry = NULL;
- }
- ASSERT(UnixSocket->State == UnixSocketStateShutdown);
- UnixSocket->State = UnixSocketStateClosed;
- KeReleaseQueuedLock(UnixSocket->Lock);
- IoSocketReleaseReference(&(UnixSocket->KernelSocket));
- return STATUS_SUCCESS;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- IopUnixSocketEnsureConnected (
- PUNIX_SOCKET Socket,
- BOOL Write
- )
- /*++
- Routine Description:
- This routine ensures a socket is connected and okay to send data. This
- routine assumes the socket lock is already held.
- Arguments:
- Socket - Supplies a pointer to the socket to check.
- Write - Supplies a boolean indicating if the caller is going to do a write
- operation on the socket (TRUE) or a read operation (FALSE).
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- Status = STATUS_SUCCESS;
- if (Write != FALSE) {
- if (Socket->State == UnixSocketStateShutdownRead) {
- return STATUS_SUCCESS;
- } else if ((Socket->State == UnixSocketStateShutdownWrite) ||
- (Socket->State == UnixSocketStateShutdown)) {
- return STATUS_BROKEN_PIPE;
- }
- } else {
- if (Socket->State == UnixSocketStateShutdownWrite) {
- return STATUS_SUCCESS;
- } else if ((Socket->State == UnixSocketStateShutdownRead) ||
- (Socket->State == UnixSocketStateShutdown)) {
- return STATUS_END_OF_FILE;
- }
- }
- if (Socket->State != UnixSocketStateConnected) {
- if (Socket->KernelSocket.Type == NetSocketDatagram) {
- if ((Socket->State != UnixSocketStateInitialized) &&
- (Socket->State != UnixSocketStateBound)) {
- Status = STATUS_BROKEN_PIPE;
- }
- } else {
- Status = STATUS_NOT_CONNECTED;
- }
- }
- return Status;
- }
- VOID
- IopUnixSocketFlushData (
- PUNIX_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine flushes all incoming data on the given socket. This routine
- assumes the socket lock is already held.
- Arguments:
- Socket - Supplies a pointer to the socket to flush.
- Return Value:
- Status code.
- --*/
- {
- PUNIX_SOCKET_PACKET Packet;
- while (LIST_EMPTY(&(Socket->ReceiveList)) == FALSE) {
- Packet = LIST_VALUE(Socket->ReceiveList.Next,
- UNIX_SOCKET_PACKET,
- ListEntry);
- LIST_REMOVE(&(Packet->ListEntry));
- KeAcquireQueuedLock(Packet->Sender->Lock);
- ASSERT(Packet->Sender->SendListSize >= Packet->Length);
- IoSetIoObjectState(Packet->Sender->KernelSocket.IoState,
- POLL_EVENT_OUT,
- TRUE);
- Packet->Sender->SendListSize -= Packet->Length;
- KeReleaseQueuedLock(Packet->Sender->Lock);
- IopUnixSocketDestroyPacket(Packet);
- }
- return;
- }
- KSTATUS
- IopUnixSocketCreatePacket (
- PUNIX_SOCKET Sender,
- PIO_BUFFER IoBuffer,
- UINTN Offset,
- UINTN DataSize,
- PUNIX_SOCKET_PACKET *NewPacket
- )
- /*++
- Routine Description:
- This routine creates a socket packet structure, and takes a reference on
- the sender on success.
- Arguments:
- Sender - Supplies a pointer to the socket sending the data.
- IoBuffer - Supplies a pointer to the I/O buffer to base the data on. A
- copy of this data will be made.
- Offset - Supplies the offset from the start of the I/O buffer to copy from.
- DataSize - Supplies the number of bytes to send.
- NewPacket - Supplies a pointer where a pointer to a newly allocated packet
- will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- UINTN AllocationSize;
- PUNIX_SOCKET_PACKET Packet;
- KSTATUS Status;
- AllocationSize = sizeof(UNIX_SOCKET_PACKET) + DataSize;
- Packet = MmAllocatePagedPool(AllocationSize, UNIX_SOCKET_ALLOCATION_TAG);
- if (Packet == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- Packet->Sender = Sender;
- Packet->Data = (PVOID)(Packet + 1);
- Packet->Length = DataSize;
- Packet->Offset = 0;
- Packet->Credentials.ProcessId = -1;
- Packet->Credentials.UserId = -1;
- Packet->Credentials.GroupId = -1;
- Packet->Handles = NULL;
- Packet->HandleCount = 0;
- if (DataSize != 0) {
- Status = MmCopyIoBufferData(IoBuffer,
- Packet->Data,
- Offset,
- DataSize,
- FALSE);
- if (!KSUCCESS(Status)) {
- MmFreePagedPool(Packet);
- return Status;
- }
- }
- IoSocketAddReference(&(Sender->KernelSocket));
- *NewPacket = Packet;
- return STATUS_SUCCESS;;
- }
- VOID
- IopUnixSocketDestroyPacket (
- PUNIX_SOCKET_PACKET Packet
- )
- /*++
- Routine Description:
- This routine destroys a socket packet structure.
- Arguments:
- Packet - Supplies a pointer to the packet to destroy.
- Return Value:
- None.
- --*/
- {
- UINTN Index;
- PIO_HANDLE *IoHandleArray;
- //
- // Release any handles and free the array if present.
- //
- IoHandleArray = Packet->Handles;
- if (IoHandleArray != NULL) {
- for (Index = 0; Index < Packet->HandleCount; Index += 1) {
- IoIoHandleReleaseReference(IoHandleArray[Index]);
- }
- MmFreePagedPool(IoHandleArray);
- }
- IoSocketReleaseReference(&(Packet->Sender->KernelSocket));
- MmFreePagedPool(Packet);
- return;
- }
- KSTATUS
- IopUnixSocketSendControlData (
- BOOL FromKernelMode,
- PUNIX_SOCKET Sender,
- PUNIX_SOCKET_PACKET Packet,
- PVOID ControlData,
- UINTN ControlDataSize
- )
- /*++
- Routine Description:
- This routine parses and attaches ancillary data to a packet.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the send is originating
- from user mode (FALSE) or kernel mode (TRUE). If user mode, then the
- control data pointer is expected to be a user mode pointer.
- Sender - Supplies a pointer to the socket doing the sending.
- Packet - Supplies a pointer to the packet that will be sent.
- ControlData - Supplies a pointer to the control data.
- ControlDataSize - Supplies the size of the control data.
- Return Value:
- Status code.
- --*/
- {
- UINTN AllocationSize;
- PSOCKET_CONTROL_MESSAGE Control;
- PVOID ControlDataCopy;
- PUNIX_SOCKET_CREDENTIALS Credentials;
- PHANDLE DescriptorArray;
- UINTN DescriptorCount;
- UINTN DescriptorIndex;
- PIO_HANDLE *IoHandleArray;
- UINTN IoHandleCount;
- PKPROCESS Process;
- KSTATUS Status;
- PKTHREAD Thread;
- UINTN TotalDescriptorCount;
- ControlDataCopy = NULL;
- IoHandleArray = NULL;
- IoHandleCount = 0;
- ASSERT(FromKernelMode == FALSE);
- if (ControlDataSize > UNIX_SOCKET_MAX_CONTROL_DATA) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketSendControlDataEnd;
- }
- Process = PsGetCurrentProcess();
- //
- // Make a copy of the control data to avoid a million tiny accesses to user
- // mode memory.
- //
- ControlDataCopy = MmAllocatePagedPool(ControlDataSize,
- UNIX_SOCKET_ALLOCATION_TAG);
- if (ControlDataCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UnixSocketSendControlDataEnd;
- }
- Status = MmCopyFromUserMode(ControlDataCopy, ControlData, ControlDataSize);
- if (!KSUCCESS(Status)) {
- goto UnixSocketSendControlDataEnd;
- }
- //
- // Loop once to count the number of file descriptors.
- //
- TotalDescriptorCount = 0;
- Control = SOCKET_CONTROL_FIRST(ControlDataCopy, ControlDataSize);
- while (Control != NULL) {
- if (Control->Protocol != SOCKET_LEVEL_SOCKET) {
- Status = STATUS_NOT_SUPPORTED;
- goto UnixSocketSendControlDataEnd;
- }
- if (Control->Type == SOCKET_CONTROL_RIGHTS) {
- //
- // TODO: HANDLE won't work in 64-bit, as PVOID will go to 8
- // bytes but the C library int will stay at 4. Create a new
- // DESCRIPTOR type that is always 32-bits, and use that as the Ob
- // handle table type.
- //
- ASSERT(sizeof(HANDLE) == sizeof(int));
- DescriptorCount = (Control->Length - SOCKET_CONTROL_LENGTH(0)) /
- sizeof(HANDLE);
- TotalDescriptorCount += DescriptorCount;
- } else if (Control->Type != SOCKET_CONTROL_CREDENTIALS) {
- Status = STATUS_NOT_SUPPORTED;
- goto UnixSocketSendControlDataEnd;
- }
- SOCKET_CONTROL_NEXT(ControlDataCopy, ControlDataSize, Control);
- }
- //
- // Allocate the handle array if needed.
- //
- if (TotalDescriptorCount > 0) {
- if (TotalDescriptorCount > UNIX_SOCKET_MAX_CONTROL_HANDLES) {
- Status = STATUS_INVALID_PARAMETER;
- goto UnixSocketSendControlDataEnd;
- }
- AllocationSize = sizeof(PIO_HANDLE) * TotalDescriptorCount;
- IoHandleArray = MmAllocatePagedPool(AllocationSize,
- UNIX_SOCKET_ALLOCATION_TAG);
- if (IoHandleArray == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UnixSocketSendControlDataEnd;
- }
- RtlZeroMemory(IoHandleArray, AllocationSize);
- }
- //
- // Go through the control messages again and populate the data.
- //
- Control = SOCKET_CONTROL_FIRST(ControlDataCopy, ControlDataSize);
- while (Control != NULL) {
- ASSERT(Control->Protocol == SOCKET_LEVEL_SOCKET);
- //
- // For passing descriptors, loop through all descriptors getting their
- // associated I/O handles. The routine that gets the handles adds a
- // reference on them, which is left there as the I/O handle sits in the
- // array.
- //
- if (Control->Type == SOCKET_CONTROL_RIGHTS) {
- DescriptorArray = SOCKET_CONTROL_DATA(Control);
- ASSERT(sizeof(HANDLE) == sizeof(int));
- DescriptorCount = (Control->Length - SOCKET_CONTROL_LENGTH(0)) /
- sizeof(HANDLE);
- for (DescriptorIndex = 0;
- DescriptorIndex < DescriptorCount;
- DescriptorIndex += 1) {
- IoHandleArray[IoHandleCount] = ObGetHandleValue(
- Process->HandleTable,
- DescriptorArray[DescriptorIndex],
- NULL);
- if (IoHandleArray[IoHandleCount] == NULL) {
- Status = STATUS_INVALID_HANDLE;
- goto UnixSocketSendControlDataEnd;
- }
- IoHandleCount += 1;
- }
- } else {
- ASSERT(Control->Type == SOCKET_CONTROL_CREDENTIALS);
- Credentials = SOCKET_CONTROL_DATA(Control);
- if ((Control->Length - SOCKET_CONTROL_LENGTH(0)) <
- sizeof(UNIX_SOCKET_CREDENTIALS)) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto UnixSocketSendControlDataEnd;
- }
- Thread = KeGetCurrentThread();
- //
- // Validate the credentials, unless the user has the proper
- // permissions to send forgeries.
- //
- Status = PsCheckPermission(PERMISSION_SYSTEM_ADMINISTRATOR);
- if ((!KSUCCESS(Status)) &&
- (Credentials->ProcessId != Process->Identifiers.ProcessId)) {
- goto UnixSocketSendControlDataEnd;
- }
- Status = PsCheckPermission(PERMISSION_SET_USER_ID);
- if ((!KSUCCESS(Status)) &&
- (Credentials->UserId != Thread->Identity.RealUserId) &&
- (Credentials->UserId != Thread->Identity.EffectiveUserId) &&
- (Credentials->UserId != Thread->Identity.SavedUserId)) {
- goto UnixSocketSendControlDataEnd;
- }
- Status = PsCheckPermission(PERMISSION_SET_GROUP_ID);
- if ((!KSUCCESS(Status)) &&
- (Credentials->GroupId != Thread->Identity.RealGroupId) &&
- (Credentials->GroupId != Thread->Identity.EffectiveGroupId) &&
- (Credentials->GroupId != Thread->Identity.SavedGroupId)) {
- goto UnixSocketSendControlDataEnd;
- }
- //
- // The sent credentials passed, add them in the packet.
- //
- Packet->Credentials.ProcessId = Credentials->ProcessId;
- Packet->Credentials.UserId = Credentials->UserId;
- Packet->Credentials.GroupId = Credentials->GroupId;
- }
- SOCKET_CONTROL_NEXT(ControlDataCopy, ControlDataSize, Control);
- }
- ASSERT(IoHandleCount == TotalDescriptorCount);
- Packet->Handles = IoHandleArray;
- Packet->HandleCount = IoHandleCount;
- IoHandleArray = NULL;
- Status = STATUS_SUCCESS;
- UnixSocketSendControlDataEnd:
- if (ControlDataCopy != NULL) {
- MmFreePagedPool(ControlDataCopy);
- }
- if (IoHandleArray != NULL) {
- for (DescriptorIndex = 0;
- DescriptorIndex < IoHandleCount;
- DescriptorIndex += 1) {
- IoIoHandleReleaseReference(IoHandleArray[DescriptorIndex]);
- }
- MmFreePagedPool(IoHandleArray);
- }
- return Status;
- }
- KSTATUS
- IopUnixSocketReceiveControlData (
- BOOL FromKernelMode,
- PUNIX_SOCKET Socket,
- PUNIX_SOCKET_PACKET Packet,
- PSOCKET_IO_PARAMETERS Parameters
- )
- /*++
- Routine Description:
- This routine receives ancillary data.
- Arguments:
- FromKernelMode - Supplies a boolean indicating if the receive is
- originating from user mode (FALSE) or kernel mode (TRUE). If user mode,
- then the control data pointer is expected to be a user mode pointer.
- Socket - Supplies a pointer to the receiving socket.
- Packet - Supplies a pointer to the packet that is being received.
- Parameters - Supplies a pointer to the I/O parameters.
- Return Value:
- Status code. Truncation or not receiving the ancillary data is not a
- failure.
- --*/
- {
- PSOCKET_CONTROL_MESSAGE Control;
- PVOID ControlData;
- UINTN ControlSize;
- PHANDLE DescriptorArray;
- UINTN Index;
- PKPROCESS Process;
- KSTATUS Status;
- //
- // Compute the size of the control data needed.
- //
- ControlSize = 0;
- if ((Packet->Credentials.ProcessId != -1) ||
- (Packet->Credentials.UserId != -1) ||
- (Packet->Credentials.GroupId != -1)) {
- ControlSize += SOCKET_CONTROL_SPACE(sizeof(UNIX_SOCKET_CREDENTIALS));
- }
- if (Packet->HandleCount != 0) {
- ASSERT(sizeof(HANDLE) == sizeof(int));
- ControlSize += SOCKET_CONTROL_SPACE(
- sizeof(HANDLE) * Packet->HandleCount);
- }
- if (ControlSize == 0) {
- Parameters->ControlDataSize = 0;
- return STATUS_SUCCESS;
- }
- //
- // There is ancillary data to be received. If the caller didn't provide
- // a buffer, then do nothing. Perhaps this is a stream socket and they're
- // only partially receiving the buffer, in which case they get another shot
- // when they receive the rest.
- //
- if ((Parameters->ControlData == NULL) ||
- (Parameters->ControlDataSize < ControlSize)) {
- Parameters->SocketIoFlags |= SOCKET_IO_CONTROL_TRUNCATED;
- return STATUS_SUCCESS;
- }
- //
- // Construct the complete control buffer in kernel mode.
- //
- ControlData = MmAllocatePagedPool(ControlSize, UNIX_SOCKET_ALLOCATION_TAG);
- if (ControlData == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UnixSocketReceiveControlDataEnd;
- }
- //
- // Zero the buffer to avoid leaking uninitialized kernel pool to user mode.
- //
- RtlZeroMemory(ControlData, ControlSize);
- Control = SOCKET_CONTROL_FIRST(ControlData, ControlSize);
- if (((Socket->Flags & UNIX_SOCKET_FLAG_SEND_CREDENTIALS) != 0) &&
- ((Packet->Credentials.ProcessId != -1) ||
- (Packet->Credentials.UserId != -1) ||
- (Packet->Credentials.GroupId != -1))) {
- Control->Length = SOCKET_CONTROL_LENGTH(
- sizeof(UNIX_SOCKET_CREDENTIALS));
- Control->Protocol = SOCKET_LEVEL_SOCKET;
- Control->Type = SOCKET_CONTROL_CREDENTIALS;
- RtlCopyMemory(SOCKET_CONTROL_DATA(Control),
- &(Packet->Credentials),
- sizeof(UNIX_SOCKET_CREDENTIALS));
- Packet->Credentials.ProcessId = -1;
- Packet->Credentials.UserId = -1;
- Packet->Credentials.GroupId = -1;
- SOCKET_CONTROL_NEXT(ControlData, ControlSize, Control);
- }
- if (Packet->HandleCount != 0) {
- //
- // The kernel process doesn't have a handle table, so this would get
- // weird.
- //
- Process = PsGetCurrentProcess();
- ASSERT(FromKernelMode == FALSE);
- ASSERT(Process != PsGetKernelProcess());
- ASSERT(sizeof(HANDLE) == sizeof(int));
- Control->Length = SOCKET_CONTROL_LENGTH(
- sizeof(HANDLE) * Packet->HandleCount);
- Control->Protocol = SOCKET_LEVEL_SOCKET;
- Control->Type = SOCKET_CONTROL_RIGHTS;
- DescriptorArray = SOCKET_CONTROL_DATA(Control);
- //
- // Create the handles in the receiving process. If failure occurs,
- // the process may end up with handles it doesn't know about. These
- // handles will get cleaned up when the process exits or does something
- // drastic like closes everything.
- //
- Status = STATUS_SUCCESS;
- for (Index = 0; Index < Packet->HandleCount; Index += 1) {
- Status = ObCreateHandle(Process->HandleTable,
- Packet->Handles[Index],
- 0,
- &(DescriptorArray[Index]));
- if (!KSUCCESS(Status)) {
- //
- // If creating a handle failed, release the reference on the
- // rest of the handles, and stop.
- //
- while (Index < Packet->HandleCount) {
- IoIoHandleReleaseReference(Packet->Handles[Index]);
- Index += 1;
- }
- break;
- }
- }
- //
- // Destroy the handle array, as all the references on the handles were
- // either transferred to the handle table or explicitly released in
- // the failure case.
- //
- MmFreePagedPool(Packet->Handles);
- Packet->Handles = NULL;
- Packet->HandleCount = 0;
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveControlDataEnd;
- }
- }
- //
- // Try to copy this ancillary data buffer to user mode.
- //
- Status = MmCopyToUserMode(Parameters->ControlData,
- ControlData,
- ControlSize);
- Parameters->ControlDataSize = ControlSize;
- if (!KSUCCESS(Status)) {
- goto UnixSocketReceiveControlDataEnd;
- }
- Status = STATUS_SUCCESS;
- UnixSocketReceiveControlDataEnd:
- if (ControlData != NULL) {
- MmFreePagedPool(ControlData);
- }
- return Status;
- }
- VOID
- IopUnixSocketInitializeCredentials (
- PUNIX_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine initializes the credentials in the given socket.
- Arguments:
- Socket - Supplies a pointer to the socket to initialize.
- Return Value:
- None.
- --*/
- {
- PKPROCESS Process;
- PKTHREAD Thread;
- Thread = KeGetCurrentThread();
- Process = PsGetCurrentProcess();
- Socket->Credentials.ProcessId = Process->Identifiers.ProcessId;
- Socket->Credentials.UserId = Thread->Identity.RealUserId;
- Socket->Credentials.GroupId = Thread->Identity.RealGroupId;
- return;
- }
|