The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcap_GSource.c
Go to the documentation of this file.
1 
43 #include <memory.h>
44 #include <projectcommon.h>
45 #include <proj_classes.h>
46 #include <pcap_min.h>
47 #include <pcap_GSource.h>
48 #include <intframe.h>
49 #include <addrframe.h>
50 #include <cstringframe.h>
51 #include <frametypes.h>
52 #include <misc.h>
53 
59 
60 FSTATIC gboolean g_source_pcap_prepare(GSource* source, gint* timeout);
61 FSTATIC gboolean g_source_pcap_check(GSource* source);
62 FSTATIC gboolean g_source_pcap_dispatch(GSource* source, GSourceFunc callback, gpointer user_data);
63 FSTATIC void g_source_pcap_finalize(GSource* source);
64 FSTATIC guint64 proj_timeval_to_g_real_time(const struct timeval * tv);
65 
66 static GSourceFuncs g_source_pcap_gsourcefuncs = {
71  NULL,
72  NULL
73 };
74 
75 
85 GSource*
86 g_source_pcap_new(const char * dev,
87  unsigned listenmask,
88  gboolean (*dispatch)(GSource_pcap_t* gsource,
90  pcap_t* capstruct,
91  gconstpointer pkt,
92  gconstpointer pend,
93  const struct pcap_pkthdr* pkthdr,
94  const char * capturedev,
95  gpointer userdata),
96 
97  GDestroyNotify notify,
98  gint priority,
100  gboolean can_recurse,
102  GMainContext* context,
103  gsize objectsize,
104  gpointer userdata
105  )
106 {
107  pcap_t* captureobj;
108  GSource* src;
109  GSource_pcap_t* ret;
110 
111  if (objectsize < sizeof(GSource_pcap_t)) {
112  objectsize = sizeof(GSource_pcap_t);
113  }
114 
115  // Try and create a GSource object for us to eventually return...
116  src = g_source_new(&g_source_pcap_gsourcefuncs, objectsize);
117  g_return_val_if_fail(src != NULL, NULL);
118 
119  proj_class_register_object(src, "GSource");
120  proj_class_register_subclassed(src, "GSource_pcap_t");
121 
122  ret = CASTTOCLASS(GSource_pcap_t, src);
123  // OK, now create the capture object to associate with it
124  if (NULL == (captureobj = create_pcap_listener(dev, FALSE, listenmask, &ret->pcprog))) {
125  // OOPS! Didn't work... Give up.
126  g_source_unref(src);
127  return NULL;
128  }
129  ret->capture = captureobj;
130  ret->capturedev = g_strdup(dev);
131  ret->listenmask = listenmask;
132  ret->dispatch = dispatch;
133 #ifdef _MSC_VER
134  // Probably depends on the version of the API - not just being on Windows...
135  ret->capturefd = pcap_fileno(ret->capture);
136 #else
137  ret->capturefd = pcap_get_selectable_fd(ret->capture);
138 #endif
139  ret->destroynote = notify;
140  ret->gfd.fd = ret->capturefd;
141  ret->gfd.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
142  ret->gfd.revents = 0;
143  ret->userdata = userdata;
144  g_source_add_poll(src, &ret->gfd);
145  g_source_set_priority(src, priority);
146  g_source_set_can_recurse(src, can_recurse);
147  ret->gsourceid = g_source_attach(src, context);
148  if (ret->gsourceid == 0) {
149  g_source_remove_poll(src, &ret->gfd);
150  memset(ret, 0, sizeof(*ret));
151  g_source_unref(src);
152  src = NULL;
153  ret = NULL;
154  }
155  return (GSource*)ret;
156 }
157 
159 gboolean
160 g_source_pcap_prepare(GSource* source,
161  gint* timeout)
162 {
163  // Don't need to do anything prior to a poll(2) call...
164  (void)source;
165  (void)timeout;
166  return FALSE;
167 }
169 gboolean
170 g_source_pcap_check(GSource* src)
171 {
173 
174  // revents: received events...
175  // @todo: should check for errors in revents
176  return 0 != psrc->gfd.revents;
177 }
179 gboolean
181  GSourceFunc callback,
182  gpointer user_data)
183 {
185  const u_char * pkt;
186  struct pcap_pkthdr* hdr;
187  int rc; // Meaning of various rc values:
188  // 1 - read a single packet
189  // 0 - no packets to read at the moment
190  // negative - various kinds of errors
191  (void)callback;
192  (void)user_data;
193  // Process all the packets we can find.
194  while (1 == (rc = pcap_next_ex(psrc->capture, &hdr, &pkt))) {
195  const u_char* pktend = pkt + hdr->caplen;
196  if (!psrc->dispatch(psrc, psrc->capture, pkt, pktend, hdr,
197  psrc->capturedev, psrc->userdata)) {
198  g_source_remove_poll(src, &psrc->gfd);
199  g_source_unref(src);
200  return FALSE;
201  }
202  }
203  // @todo: should check for errors in 'rc'
204  return rc >= 0;
205 }
208 void
210 {
212  if (psrc->destroynote) {
213  psrc->destroynote(psrc);
214  }
215  if (psrc->capture) {
216  close_pcap_listener(psrc->capture, psrc->capturedev, psrc->listenmask);
217  pcap_freecode(&psrc->pcprog);
218  psrc->capture = NULL;
219  g_free(psrc->capturedev);
220  psrc->capturedev = NULL;
221  }
223 }
224 
226 FSTATIC guint64
227 proj_timeval_to_g_real_time(const struct timeval * tv)
228 {
229  guint64 ret;
230  ret = (guint64)tv->tv_sec * (guint64)1000000UL;
231  ret += (guint64)tv->tv_usec;
232  return ret;
233 }
234 
236 FrameSet*
237 construct_pcap_frameset(guint16 framesettype,
238  gconstpointer pkt,
239  gconstpointer pktend,
240  const struct pcap_pkthdr* pkthdr,
241  const char * interfacep)
242 {
244  Frame* pktframe = frame_new(FRAMETYPE_PKTDATA, 0);
247  FrameSet* fs = frameset_new(framesettype);
248  const guint8* bpkt = (const guint8*) pkt;
249  gsize pktlen = ((const guint8*)pktend-bpkt);
250  guint8* cppkt = MALLOC0(pktlen);
251  gchar* sysname;
252 
253  sysname = proj_get_sysname();
254  g_return_val_if_fail(NULL != sysname, NULL);
255  g_return_val_if_fail(fsysname != NULL, NULL);
256  g_return_val_if_fail(timeframe != NULL, NULL);
257  g_return_val_if_fail(pktframe != NULL, NULL);
258  g_return_val_if_fail(intfname != NULL, NULL);
259  g_return_val_if_fail(cppkt != NULL, NULL);
260 
261  // System name
262  fsysname->baseclass.setvalue(&fsysname->baseclass, sysname, strlen(sysname)+1, g_free);
263  frameset_append_frame(fs, &fsysname->baseclass);
264  UNREF2(fsysname);
265 
266  // Interface name
267  intfname->baseclass.setvalue(&intfname->baseclass, g_strdup(interfacep), strlen(interfacep)+1, g_free);
268  frameset_append_frame(fs, &intfname->baseclass);
269  UNREF2(intfname);
270 
271  // Local time stamp
272  timeframe->setint(timeframe, proj_timeval_to_g_real_time(&(pkthdr->ts)));
273  frameset_append_frame(fs, &timeframe->baseclass);
274  UNREF2(timeframe);
275 
276  // Packet data
277  memcpy(cppkt, pkt, pktlen);
278  pktframe->setvalue(pktframe, cppkt, pktlen, g_free);
279  frameset_append_frame(fs, pktframe);
280  UNREF(pktframe);
281 
282  return fs;
283 }