1 /**************************************************************************
5 Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 Contact: Boram Park <boram1288.park@samsung.com>
8 Sangjin LEE <lsj119@samsung.com>
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 **************************************************************************/
39 #include <sys/types.h>
40 #include <sys/fcntl.h>
48 #include <sys/socket.h>
49 #include <linux/socket.h>
51 #ifdef HAS_GETPEERUCRED
57 #include <X11/Xatom.h>
58 #include <X11/extensions/XI2proto.h>
59 #include <windowstr.h>
63 #include "xdbg_module_types.h"
64 #include "xdbg_module_evlog.h"
65 #include "xdbg_module_evlog_request.h"
66 #include "xdbg_module_evlog_event.h"
67 #include "bool_exp_rule_checker.h"
72 #define FP1616toDBL(x) ((x) * 1.0 / (1 << 16))
74 static Bool xev_trace_on = FALSE;
75 static int xev_trace_fd = -1;
76 static int xev_trace_record_fd = -1;
77 static Atom atom_rotate = None;
78 static Atom atom_client_pid = None;
80 RULE_CHECKER rc = NULL;
82 #define UNKNOWN_EVENT "<unknown>"
92 #define EVTDATA_MASK_CLIENT_INFO 0x1
93 #define EVTDATA_MASK_CLIENT_REQ 0x2
94 #define EVTDATA_MASK_EVENT 0x4
96 static char *evt_type[] = { "Event", "Request", "Reply", "Flush" };
97 static char *evt_dir[] = { "<====", "---->", "<----", "*****" };
99 static void _evtPrintF (int fd, const char * format, ...)
103 va_start (args, format);
105 VErrorF (format, args);
107 vdprintf (fd, format, args);
111 static void evtGetReqInfo (evtType type, EvlogClientInfo *evinfo, xReq *req, xEvent *ev,
112 int *req_id, const char **req_string,
113 char **c_cmd, int *c_index, int *c_pid)
115 if (type == REQUEST && req)
117 *req_id = req->reqType;
118 if (req->reqType < EXTENSION_BASE)
119 *req_string = LookupRequestName (req->reqType, 0);
121 *req_string = LookupRequestName (req->reqType, req->data);
123 else if (type == EVENT && ev)
124 *req_string = LookupEventName ((int)(ev->u.u.type));
128 *c_index = evinfo->index;
129 *c_pid = evinfo->pid;
131 *c_cmd = rindex (evinfo->command, '/');
133 *c_cmd = evinfo->command;
139 static void evtRecord (CARD32 msec, evtType type, EvlogClientInfo *evinfo, xEvent *ev)
142 int write_len = sizeof (int) +
147 if (xev_trace_record_fd < 0)
152 mask |= EVTDATA_MASK_CLIENT_INFO;
153 write_len += sizeof (EvlogClientInfo);
155 if (evinfo->requestBuffer)
157 mask |= EVTDATA_MASK_CLIENT_REQ;
158 write_len += evinfo->req_len;
164 mask |= EVTDATA_MASK_EVENT;
165 write_len += sizeof (xEvent);
168 if (write (xev_trace_record_fd, &write_len, sizeof(int)) == -1)
170 XDBG_ERROR (MXDBG, "failed: write write_len\n");
173 if (write (xev_trace_record_fd, &msec, sizeof(CARD32)) == -1)
175 XDBG_ERROR (MXDBG, "failed: write msec\n");
178 if (write (xev_trace_record_fd, &type, sizeof(evtType)) == -1)
180 XDBG_ERROR (MXDBG, "failed: write type\n");
183 if (write (xev_trace_record_fd, &mask, sizeof(int)) == -1)
185 XDBG_ERROR (MXDBG, "failed: write mask\n");
191 if (write (xev_trace_record_fd, evinfo, sizeof (EvlogClientInfo)) == -1)
193 XDBG_ERROR (MXDBG, "failed: write client\n");
196 if (evinfo->requestBuffer)
197 if (write (xev_trace_record_fd, evinfo->requestBuffer, evinfo->req_len) == -1)
199 XDBG_ERROR (MXDBG, "failed: write requestBuffer\n");
205 if (write (xev_trace_record_fd, ev, sizeof (xEvent)) == -1)
207 XDBG_ERROR (MXDBG, "failed: write ev\n");
212 static void evtPrintF (int fd, CARD32 msec, evtType type, EvlogClientInfo *evinfo, xEvent *ev)
215 const char *req_string = "";
216 const char *req_detail = "";
217 char tempbuf[256] = {0,};
224 XDBG_RETURN_IF_FAIL (type >= 0 && (sizeof (evt_dir) / sizeof (char*)));
225 XDBG_RETURN_IF_FAIL (type >= 0 && (sizeof (evt_type) / sizeof (char*)));
229 req = (xReq *)evinfo->requestBuffer;
232 evtGetReqInfo (type, evinfo, req, ev, &req_id, &req_string, &c_cmd, &c_index, &c_pid);
236 XDBG_RETURN_IF_FAIL (evinfo != NULL);
237 XDBG_RETURN_IF_FAIL (req != NULL);
238 xDbgModuleEvlogReqeust (evinfo, req, tempbuf, sizeof (tempbuf));
239 req_detail = tempbuf;
241 else if (type == EVENT)
243 XDBG_RETURN_IF_FAIL (ev != NULL);
244 xDbgModuleEvlogEvent (ev, tempbuf, sizeof (tempbuf));
245 req_detail = tempbuf;
248 req_detail = req_string;
250 _evtPrintF (fd, "[%10.3f][%4ld] %15s(%2d:%4d) %s %7s (%s)\n",
253 c_cmd, c_index, c_pid,
255 evt_type[type], req_detail);
260 static void evtPrint (evtType type, ClientPtr client, xEvent *ev)
263 const char *req_string = "";
268 ModuleClientInfo *info = NULL;
269 EvlogClientInfo evinfo;
272 if (xev_trace_on == FALSE)
277 info = GetClientInfo (client);
278 XDBG_RETURN_IF_FAIL (info != NULL);
280 memset (&evinfo, 0, sizeof (EvlogClientInfo));
282 evinfo.index = info->index;
283 evinfo.pid = info->pid;
284 evinfo.gid = info->gid;
285 evinfo.uid = info->uid;
286 strncpy (evinfo.command, info->command, strlen (info->command));
287 evinfo.requestBuffer = client->requestBuffer;
288 evinfo.req_len = client->req_len;
290 req = (xReq *)evinfo.requestBuffer;
293 evtGetReqInfo (type, (client)?&evinfo:NULL, req, ev, &req_id, &req_string, &c_cmd, &c_index, &c_pid);
296 rc = rulechecker_init();
298 if (!rulechecker_validate_rule (rc, type, req_id, req_string, c_pid, c_cmd))
301 curr = GetTimeInMillis ();
303 if (xev_trace_record_fd >= 0)
304 evtRecord (curr, type, (client)?&evinfo:NULL, ev);
306 evtPrintF (xev_trace_fd, curr, type, (client)?&evinfo:NULL, ev);
309 static void _mergeArgs (char * target, int argc, const char ** argv)
314 for (i=0; i<argc; i++)
316 len = sprintf (target, "%s", argv[i]);
325 _traceGetWindowName (ClientPtr client, Window window)
329 Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
332 static char winname[128];
335 rc = dixLookupWindow (&pWin, window, client, win_mode);
339 property = MakeAtom ("WM_NAME", strlen ("WM_NAME"), TRUE);
342 rc = dixLookupProperty (&pProp, pWin, property, client, prop_mode);
343 if (rc == Success && pProp->data)
345 datalen = (pProp->size>127) ?127:pProp->size;
346 strncpy (winname, pProp->data, datalen);
347 winname[datalen] = 0;
359 _traceFlush (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
361 evtPrint (FLUSH, NULL, NULL);
365 _traceAReply (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
367 ReplyInfoRec *pri = (ReplyInfoRec*)calldata;
369 evtPrint (REPLY, pri->client, NULL);
373 _traceEvent (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
375 EventInfoRec *pei = (EventInfoRec*)calldata;
377 ModuleClientInfo *info;
378 int ev; /* event index */
379 static int xi2_opcode = -1;
381 static char* ename[]=
389 XDBG_RETURN_IF_FAIL (pei != NULL);
391 pClient = pei->client;
392 XDBG_RETURN_IF_FAIL (pClient != NULL);
395 XDBG_RETURN_IF_FAIL (pev != NULL);
397 info = GetClientInfo (pClient);
398 XDBG_RETURN_IF_FAIL (info != NULL);
400 for (ev=0; ev < pei->count; ev++, pev++)
402 int type = pev->u.u.type & 0177;
404 if (type < LASTEvent)
410 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
411 , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
412 , info->command, info->pid
413 , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
414 , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
415 , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
420 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
421 , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
422 , info->command, info->pid
423 , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
424 , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
425 , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
428 if(!xi2_opcode) break;
431 ExtensionEntry *pExt = CheckExtension("XInputExtension");
432 if(!pExt) xi2_opcode = 0;
433 else xi2_opcode = pExt->base;
436 if(((xGenericEvent*)pev)->extension != xi2_opcode) break;
438 xXIDeviceEvent *xidev = (xXIDeviceEvent *)pev;
439 if(xidev->deviceid==2) break;
440 if(xidev->evtype==XI_ButtonPress)
441 XDBG_TRACE (MXDBG, "XI_ButtonPress(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonPress, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
442 else if(xidev->evtype==XI_ButtonRelease)
443 XDBG_TRACE (MXDBG, "XI_ButtonRelease(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonRelease, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
444 else if(xidev->evtype==XI_Motion)
445 XDBG_TRACE (MXDBG, "XI_Motion(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_Motion, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
452 evtPrint (EVENT, pClient, pev);
457 _traceACoreEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
459 XaceCoreDispatchRec *rec = calldata;
461 XDBG_RETURN_IF_FAIL (rec != NULL);
463 evtPrint (REQUEST, rec->client, NULL);
467 _traceAExtEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
469 XaceExtAccessRec *rec = calldata;
471 XDBG_RETURN_IF_FAIL (rec != NULL);
473 evtPrint (REQUEST, rec->client, NULL);
477 _traceProperty (CallbackListPtr *pcbl, pointer unused, pointer calldata)
479 XacePropertyAccessRec *rec = calldata;
480 ModuleClientInfo *info = GetClientInfo (rec->client);
481 PropertyPtr pProp = *rec->ppProp;
482 Atom name = pProp->propertyName;
484 /* Don't care about the new content check */
485 if (rec->client == serverClient || rec->access_mode & DixPostAccess)
488 if (name == atom_client_pid && (rec->access_mode & DixWriteAccess))
490 XDBG_WARNING (MXDBG, "Invalid access X_CLINET_PID pid:%d, uid:%d\n", info->pid, info->uid);
491 rec->status = BadAccess;
495 rec->status = Success;
500 _traceResource (CallbackListPtr *pcbl, pointer unused, pointer calldata)
502 XaceResourceAccessRec *rec = calldata;
503 Mask access_mode = rec->access_mode;
504 ModuleClientInfo *info = GetClientInfo (rec->client);
506 /* Perform the background none check on windows */
507 if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW)
509 WindowPtr pWin = (WindowPtr) rec->res;
513 rc = dixChangeWindowProperty (serverClient,
514 pWin, atom_client_pid, XA_CARDINAL, 32,
515 PropModeReplace, 1, &pid, FALSE);
517 XDBG_ERROR (MXDBG, "failed : set X_CLIENT_PID to %d.\n", pid);
522 _traceReceive (CallbackListPtr *pcbl, pointer unused, pointer calldata)
524 XaceReceiveAccessRec *rec = calldata;
526 if (rec->events->u.u.type != VisibilityNotify)
529 rec->status = BadAccess;
533 xDbgModuleEvlogInstallHooks (XDbgModule *pMod)
537 ret &= AddCallback (&EventCallback, _traceEvent, NULL);
538 ret &= AddCallback (&FlushCallback, _traceFlush, NULL);
539 ret &= AddCallback (&ReplyCallback, _traceAReply, NULL);
540 ret &= XaceRegisterCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
541 ret &= XaceRegisterCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
543 /*Disable Visibility Event*/
544 ret &= XaceRegisterCallback (XACE_RECEIVE_ACCESS, _traceReceive, NULL);
546 if (atom_client_pid == None)
547 atom_client_pid = MakeAtom ("X_CLIENT_PID", 12, TRUE);
548 if (atom_rotate == None)
549 atom_rotate = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE", 12, TRUE);
553 XDBG_ERROR (MXDBG, "failed: register one or more callbacks\n");
557 if (pMod && pMod->evlog_path)
558 xDbgModuleEvlogSetEvlogPath (pMod, -1, pMod->evlog_path, NULL, NULL);
564 xDbgModuleEvlogUninstallHooks (XDbgModule *pMod)
566 DeleteCallback (&EventCallback, _traceEvent, NULL);
567 DeleteCallback (&FlushCallback, _traceFlush, NULL);
568 DeleteCallback (&ReplyCallback, _traceAReply, NULL);
569 XaceDeleteCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
570 XaceDeleteCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
574 xDbgModuleEvlogPrintEvents (XDbgModule *pMod, Bool on, const char * client_name, char *reply, int *len)
585 for (i=1 ; i< currentMaxClients ; i++)
588 ModuleClientInfo *info;
590 pClient = clients[i];
594 info = GetClientInfo (pClient);
598 if (strlen (info->command) > 0 && strstr (client_name, info->command))
602 if (xev_trace_fd >= 0)
603 close (xev_trace_fd);
605 snprintf (fd_name, 256, "/proc/%d/fd/1", info->pid);
606 xev_trace_fd = open (fd_name, O_RDWR);
607 if (xev_trace_fd < 0)
608 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
613 ret &= XaceRegisterCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
614 ret &= XaceRegisterCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
618 XDBG_REPLY ("failed: register one or more callbacks.\n");
624 XaceDeleteCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
625 XaceDeleteCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
632 xDbgModuleEvlogInfoSetRule (XDbgModule *pMod, const int argc, const char ** argv, char *reply, int *len)
634 const char * command;
637 rc = rulechecker_init();
641 rulechecker_print_rule (rc, reply);
647 if (!strcasecmp (command, "add"))
649 POLICY_TYPE policy_type;
650 RC_RESULT_TYPE result;
651 const char * policy = argv[1];
656 XDBG_REPLY ("Error : Too few arguments.\n");
660 if (!strcasecmp (policy, "ALLOW"))
662 else if (!strcasecmp (policy, "DENY"))
666 XDBG_REPLY ("Error : Unknown policy : [%s].\n Policy should be ALLOW or DENY.\n", policy);
670 _mergeArgs (rule, argc - 2, &(argv[2]));
672 result = rulechecker_add_rule (rc, policy_type, rule);
673 if (result == RC_ERR_TOO_MANY_RULES)
675 XDBG_REPLY ("Error : Too many rules were added.\n");
678 else if (result == RC_ERR_PARSE_ERROR)
680 XDBG_REPLY ("Error : An error occured during parsing the rule [%s]\n", rule);
684 XDBG_REPLY ("The rule was successfully added.\n\n");
685 rulechecker_print_rule (rc, reply);
688 else if (!strcasecmp (command, "remove"))
690 const char * remove_idx;
695 XDBG_REPLY ("Error : Too few arguments.\n");
699 for (i=0; i<argc - 1; i++)
701 remove_idx = argv[i+1];
703 if (!strcasecmp (remove_idx, "all"))
705 rulechecker_destroy (rc);
706 rc = rulechecker_init();
707 XDBG_REPLY ("Every rules were successfully removed.\n");
711 int index = atoi (remove_idx);
712 if (isdigit (*remove_idx) && rulechecker_remove_rule (rc, index) == 0)
713 XDBG_REPLY ("The rule [%d] was successfully removed.\n", index);
715 XDBG_REPLY ("Rule remove fail : No such rule [%s].\n", remove_idx);
718 rulechecker_print_rule (rc, reply);
721 else if (!strcasecmp (command, "print"))
723 rulechecker_print_rule (rc, reply);
726 else if (!strcasecmp (command, "help"))
728 XDBG_REPLY ("%s", rulechecker_print_usage());
732 XDBG_REPLY ("%s\nUnknown command : [%s].\n\n", rulechecker_print_usage(), command);
738 xDbgModuleEvlogSetEvlogPath (XDbgModule *pMod, int pid, char *path, char *reply, int *len)
740 char fd_name[XDBG_PATH_MAX];
741 char *temp[3] = {"/", "./", "../"};
745 if (!path || strlen (path) <= 0)
747 XDBG_REPLY ("failed: invalid path\n");
751 if (xev_trace_record_fd >= 0)
753 close (xev_trace_record_fd);
754 xev_trace_record_fd = -1;
757 if (!strcmp (path, "console"))
763 if (xev_trace_fd >= 0)
764 close (xev_trace_fd);
766 snprintf (fd_name, sizeof (fd_name), "/proc/%d/fd/1", pid);
768 xev_trace_fd = open (fd_name, O_RDWR);
769 if (xev_trace_fd < 0)
770 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
776 for (i = 0; i < sizeof (temp) / sizeof (char*); i++)
777 if (path == strstr (path, temp[i]))
785 XDBG_REPLY ("failed: invalid path(%s)\n", path);
790 snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
794 if (getcwd (cwd, sizeof (cwd)))
795 snprintf (fd_name, XDBG_PATH_MAX, "%s/%s", cwd, path);
797 snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
800 xev_trace_record_fd = open (fd_name, O_CREAT|O_RDWR|O_APPEND, 0755);
801 if (xev_trace_record_fd < 0)
803 XDBG_REPLY ("failed: open file '%s'. (%s)\n", fd_name, strerror(errno));
811 xDbgModuleEvlogPrintEvlog (XDbgModule *pMod, int pid, char *evlog_path, char *reply, int *len)
813 int fd = -1, cfd = -1;
816 pointer requestBuffer = NULL;
821 XDBG_REPLY ("failed: no evlog path\n");
825 fd = open (evlog_path, O_RDONLY);
828 XDBG_REPLY ("failed: open '%s'. (%s)\n", evlog_path, strerror(errno));
832 snprintf (fd_name, sizeof (fd_name), "/proc/%d/fd/1", pid);
833 cfd = open (fd_name, O_RDWR);
836 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
840 while ((read_len = read (fd, &evlog_len, sizeof (int))) == sizeof (int))
845 EvlogClientInfo evinfo;
850 read_len = read (fd, &msec, sizeof (CARD32));
851 XDBG_GOTO_IF_FAIL (read_len == sizeof (CARD32), print_done);
854 read_len = read (fd, &type, sizeof (evtType));
855 XDBG_GOTO_IF_FAIL (read_len == sizeof (evtType), print_done);
856 XDBG_GOTO_IF_FAIL (type >= EVENT && type <= FLUSH, print_done);
859 read_len = read (fd, &mask, sizeof (int));
860 XDBG_GOTO_IF_FAIL (read_len == sizeof (int), print_done);
863 if (mask & EVTDATA_MASK_CLIENT_INFO)
865 read_len = read (fd, &evinfo, sizeof (EvlogClientInfo));
866 XDBG_GOTO_IF_FAIL (read_len == sizeof (EvlogClientInfo), print_done);
869 if ((mask & EVTDATA_MASK_CLIENT_REQ) && (evinfo.req_len > 0))
871 requestBuffer = malloc (evinfo.req_len);
872 XDBG_GOTO_IF_FAIL (requestBuffer != NULL, print_done);
874 read_len = read (fd, requestBuffer, evinfo.req_len);
875 XDBG_GOTO_IF_FAIL (read_len == evinfo.req_len, print_done);
878 evinfo.requestBuffer = requestBuffer;
882 if (mask & EVTDATA_MASK_EVENT)
884 read_len = read (fd, &ev, sizeof (xEvent));
885 XDBG_GOTO_IF_FAIL (read_len == sizeof (xEvent), print_done);
889 XDBG_GOTO_IF_FAIL (evlog_len == total, print_done);
891 evtPrintF (cfd, msec, type, &evinfo, &ev);
895 free (requestBuffer);
896 requestBuffer = NULL;
902 free (requestBuffer);