2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Class for server objects.
9 #include <proto/exec.h>
10 #include <exec/lists.h>
11 #include <exec/memory.h>
12 #include <proto/oop.h>
14 #include <oop/server.h>
15 #include <oop/proxy.h>
22 #include <aros/debug.h>
24 /* The server class, allows you to make objects public,
25 obtain proxy objects for them from other processes.
26 Method calls on the proxies will be transferred
27 to the server using IPC, and will then be executed
28 on the proxied object. This means method invocation
36 /* List of public objects */
37 struct List ObjectList
;
39 /* The MsgPort from which the server receives invocation requests */
40 struct MsgPort
*ReceivePort
;
42 /* The public object list needs protection */
43 struct SignalSemaphore ObjectListLock
;
47 /* structure for making a list of objects */
48 struct ServerObjectNode
51 OOP_Object
*so_Object
;
55 #define OOPBase ((struct Library *)cl->UserData)
57 static OOP_Object
*_Root_New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
59 EnterFunc(bug("Server::New(cl=%s, o=%p, msg=%p)\n",
60 cl
->ClassNode
.ln_Name
, o
, msg
));
62 D(bug("DoSuperMethod: %p\n", cl
->DoSuperMethod
));
63 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
68 struct ServerData
*data
;
70 D(bug("getting instdata\n"));
72 data
= OOP_INST_DATA(cl
, o
);
73 D(bug("got instdata\n"));
75 disp_mid
= OOP_GetMethodID(IID_Root
, moRoot_Dispose
);
76 D(bug("got dispmid\n"));
77 /* Clear so we can test what resources are allocated in Dispose() */
78 D(bug("Object created, o=%p, data=%p\n", o
, data
));
79 memset(data
, 0, sizeof (struct ServerData
));
81 D(bug("Object instdata cleared\n"));
82 NEWLIST(&data
->ObjectList
);
83 InitSemaphore(&data
->ObjectListLock
);
85 /* Set up port for receiving incoming invocation requests */
86 D(bug("Creating receive msgport\n"));
88 data
->ReceivePort
= CreateMsgPort();
89 if (data
->ReceivePort
)
92 ReturnPtr("Server::New", OOP_Object
*, o
);
94 OOP_CoerceMethod(cl
, o
, (OOP_Msg
)&disp_mid
);
97 ReturnPtr ("Server::New", OOP_Object
*, NULL
);
100 static VOID
_Root_Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
102 struct Node
*node
, *nextnode
;
103 struct ServerData
*data
= OOP_INST_DATA(cl
, o
);
105 EnterFunc(bug("Server::Dispose()\n"));
107 node
= data
->ObjectList
.lh_Head
;
109 /* Free all nodes in the list */
110 while ((nextnode
= node
->ln_Succ
))
113 FreeVec(node
->ln_Name
);
114 FreeMem(node
, sizeof (struct ServerObjectNode
));
119 /* Free the invocation request port */
120 if(data
->ReceivePort
)
121 DeleteMsgPort(data
->ReceivePort
);
123 ReturnVoid("Server::Dispose");
127 /*****************************
128 ** IServer implementation **
129 *****************************/
131 /* Add an object to the list of public objects. */
133 static BOOL
_Server_AddObject(OOP_Class
*cl
, OOP_Object
*o
, struct P_Server_AddObject
*msg
)
135 struct ServerData
*data
= OOP_INST_DATA(cl
, o
);
137 struct ServerObjectNode
*so
;
139 EnterFunc(bug("Server::AddObject(obj=%p, id=%s)\n", msg
->Object
, msg
->ObjectID
));
141 /* Allocate list node */
142 so
= AllocMem(sizeof (struct ServerObjectNode
), MEMF_ANY
);
145 /* Copy the object ID */
146 so
->so_Node
.ln_Name
= AllocVec(strlen(msg
->ObjectID
) + 1, MEMF_ANY
);
147 if (so
->so_Node
.ln_Name
)
149 strcpy(so
->so_Node
.ln_Name
, msg
->ObjectID
);
150 so
->so_Object
= msg
->Object
;
152 /* Add it to the list */
153 ObtainSemaphore(&data
->ObjectListLock
);
154 AddTail(&data
->ObjectList
, (struct Node
*)so
);
155 ReleaseSemaphore(&data
->ObjectListLock
);
157 ReturnBool ("Server::AddObject", TRUE
);
159 FreeMem(so
, sizeof (struct ServerObjectNode
));
161 ReturnBool ("Server::AddObject", FALSE
);
164 /* Remove a previosly added object */
165 static VOID
_Server_RemoveObject(OOP_Class
*cl
, OOP_Object
*o
, struct P_Server_RemoveObject
*msg
)
167 struct ServerData
*data
= OOP_INST_DATA(cl
, o
);
169 struct ServerObjectNode
*so
;
171 EnterFunc(bug("Server::RemoveObject(objid=%s)\n", msg
->ObjectID
));
173 ObtainSemaphore(&data
->ObjectListLock
);
175 /* Find the object */
176 so
= (struct ServerObjectNode
*)FindName(&data
->ObjectList
, msg
->ObjectID
);
179 /* ..and remove it */
180 Remove((struct Node
*)so
);
181 FreeVec(so
->so_Node
.ln_Name
);
182 FreeMem(so
, sizeof (struct ServerObjectNode
) );
184 ReleaseSemaphore(&data
->ObjectListLock
);
186 ReturnVoid("Server::RemoveObject");
189 /* Find a public object */
190 static OOP_Object
* _Server_FindObject(OOP_Class
*cl
, OOP_Object
*o
, struct P_Server_FindObject
*msg
)
192 struct ServerObjectNode
*so
;
193 struct ServerData
*data
= OOP_INST_DATA(cl
, o
);
195 EnterFunc(bug("Server::FindObject(objid=%s)\n", msg
->ObjectID
));
197 /* See if the server knows about the object */
198 ObtainSemaphoreShared(&data
->ObjectListLock
);
199 /* Search for object */
200 so
= (struct ServerObjectNode
*)FindName(&data
->ObjectList
, msg
->ObjectID
);
201 ReleaseSemaphore(&data
->ObjectListLock
);
205 /* If found, create a proxy for the object */
206 struct TagItem proxy_tags
[] =
208 {aProxy_RealObject
, (IPTR
)so
->so_Object
},
209 {aProxy_Port
, (IPTR
)data
->ReceivePort
},
215 proxy
= OOP_NewObject(NULL
, CLID_Proxy
, proxy_tags
);
218 ReturnPtr("Server::FindObject", OOP_Object
*, proxy
);
222 ReturnPtr("Server::FindObject", OOP_Object
*, NULL
);
224 /* Let the server wait forevere, executing and replying
225 answering to all incoming method invocation requests
227 static VOID
_Server_Run(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
229 struct ServerData
*data
= OOP_INST_DATA(cl
, o
);
234 /* Wait for incoming invocation request */
235 WaitPort(data
->ReceivePort
);
237 while ( (pm
= (struct ProxyMsg
*)GetMsg(data
->ReceivePort
)) )
240 pm
->pm_RetVal
= OOP_DoMethod(pm
->pm_Object
, pm
->pm_ObjMsg
);
242 /* Reply back to task invoking */
243 ReplyMsg((struct Message
*)pm
);
253 OOP_Class
*init_serverclass(struct Library
*OOPBase
)
256 struct OOP_MethodDescr root_methods
[] =
258 {(IPTR (*)())_Root_New
, moRoot_New
},
259 {(IPTR (*)())_Root_Dispose
, moRoot_Dispose
},
263 struct OOP_MethodDescr server_methods
[] =
265 {(IPTR (*)())_Server_AddObject
, moServer_AddObject
},
266 {(IPTR (*)())_Server_RemoveObject
, moServer_RemoveObject
},
267 {(IPTR (*)())_Server_FindObject
, moServer_FindObject
},
268 {(IPTR (*)())_Server_Run
, moServer_Run
},
272 struct OOP_InterfaceDescr ifdescr
[] =
274 { root_methods
, IID_Root
, 2},
275 { server_methods
, IID_Server
, 4},
279 struct TagItem tags
[] =
281 {aMeta_SuperID
, (IPTR
)CLID_Root
},
282 {aMeta_InterfaceDescr
, (IPTR
)ifdescr
},
283 {aMeta_ID
, (IPTR
)CLID_Server
},
284 {aMeta_InstSize
, (IPTR
)sizeof (struct ServerData
)},
291 EnterFunc(bug("InitServerClass()\n"));
293 cl
= (OOP_Class
*)OOP_NewObject(NULL
, CLID_MIMeta
, tags
);
296 cl
->UserData
= OOPBase
;
300 ReturnPtr ("InitServerClass", OOP_Class
*, cl
);