| 1 | /* |
|---|
| 2 | * Perl bindings for the remctl client library. |
|---|
| 3 | * |
|---|
| 4 | * This is an XS source file, suitable for processing by xsubpp, that |
|---|
| 5 | * generates Perl bindings for the libremctl client library. It supports |
|---|
| 6 | * both the simplified interface (via a simple remctl call) and the more |
|---|
| 7 | * complex interface (returning a Net::Remctl object which is then used for |
|---|
| 8 | * subsequent calls). |
|---|
| 9 | * |
|---|
| 10 | * The remctl opaque struct is mapped to a Net::Remctl object and supports |
|---|
| 11 | * methods equivalent to the library functions prefixed by remctl_ that take |
|---|
| 12 | * struct remctl * as their first argument. remctl_new() is mapped to the |
|---|
| 13 | * new method of the class. remctl_output structs are returned as |
|---|
| 14 | * Net::Remctl::Output objects with accessor functions that return the |
|---|
| 15 | * elements of the remctl_output struct. The types (output, status, error, |
|---|
| 16 | * and done) are returned as lowercase strings rather than as numeric |
|---|
| 17 | * constants. |
|---|
| 18 | * |
|---|
| 19 | * The simple interface is available via an exported remctl function which |
|---|
| 20 | * returns a Net::Remctl::Result object with accessor functions for the |
|---|
| 21 | * members of the struct. |
|---|
| 22 | * |
|---|
| 23 | * Written by Russ Allbery <rra@stanford.edu> |
|---|
| 24 | * Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University |
|---|
| 25 | * |
|---|
| 26 | * See LICENSE for licensing terms. |
|---|
| 27 | */ |
|---|
| 28 | |
|---|
| 29 | #include <EXTERN.h> |
|---|
| 30 | #include <perl.h> |
|---|
| 31 | #include <XSUB.h> |
|---|
| 32 | |
|---|
| 33 | #include <errno.h> |
|---|
| 34 | |
|---|
| 35 | #include <remctl.h> |
|---|
| 36 | |
|---|
| 37 | /* |
|---|
| 38 | * These typedefs are needed for xsubpp to work its magic with type |
|---|
| 39 | * translation to Perl objects. |
|---|
| 40 | */ |
|---|
| 41 | typedef struct remctl * Net__Remctl; |
|---|
| 42 | typedef struct remctl_result * Net__Remctl__Result; |
|---|
| 43 | typedef struct remctl_output * Net__Remctl__Output; |
|---|
| 44 | |
|---|
| 45 | /* Map the remctl_output type constants to strings. */ |
|---|
| 46 | const struct { |
|---|
| 47 | enum remctl_output_type type; |
|---|
| 48 | const char *name; |
|---|
| 49 | } OUTPUT_TYPE[] = { |
|---|
| 50 | { REMCTL_OUT_OUTPUT, "output" }, |
|---|
| 51 | { REMCTL_OUT_STATUS, "status" }, |
|---|
| 52 | { REMCTL_OUT_ERROR, "error" }, |
|---|
| 53 | { REMCTL_OUT_DONE, "done" }, |
|---|
| 54 | { 0, NULL } |
|---|
| 55 | }; |
|---|
| 56 | |
|---|
| 57 | /* XS code below this point. */ |
|---|
| 58 | |
|---|
| 59 | MODULE = Net::Remctl PACKAGE = Net::Remctl PREFIX = remctl_ |
|---|
| 60 | |
|---|
| 61 | PROTOTYPES: ENABLE |
|---|
| 62 | |
|---|
| 63 | Net::Remctl::Result |
|---|
| 64 | remctl(host, port, principal, ...) |
|---|
| 65 | const char *host |
|---|
| 66 | unsigned short port |
|---|
| 67 | const char *principal |
|---|
| 68 | PREINIT: |
|---|
| 69 | size_t count = items - 3; |
|---|
| 70 | size_t i; |
|---|
| 71 | const char **command; |
|---|
| 72 | CODE: |
|---|
| 73 | if (items <= 3) |
|---|
| 74 | croak("Too few arguments to Net::Remctl::remctl"); |
|---|
| 75 | if (principal != NULL && *principal == '\0') |
|---|
| 76 | principal = NULL; |
|---|
| 77 | command = malloc(sizeof(char *) * (count + 1)); |
|---|
| 78 | if (command == NULL) |
|---|
| 79 | croak("Error allocating memory in Net::Remctl::remctl: %s", |
|---|
| 80 | strerror(errno)); |
|---|
| 81 | for (i = 0; i <= count; i++) |
|---|
| 82 | command[i] = SvPV_nolen(ST(i + 3)); |
|---|
| 83 | command[count] = NULL; |
|---|
| 84 | RETVAL = remctl(host, port, principal, command); |
|---|
| 85 | if (RETVAL == NULL) |
|---|
| 86 | croak("Error creating Net::Remctl::Result object: %s", |
|---|
| 87 | strerror(errno)); |
|---|
| 88 | free(command); |
|---|
| 89 | OUTPUT: |
|---|
| 90 | RETVAL |
|---|
| 91 | |
|---|
| 92 | Net::Remctl |
|---|
| 93 | remctl_new(class) |
|---|
| 94 | const char *class |
|---|
| 95 | CODE: |
|---|
| 96 | RETVAL = remctl_new(); |
|---|
| 97 | if (RETVAL == NULL) |
|---|
| 98 | croak("Error creating %s object: %s", class, strerror(errno)); |
|---|
| 99 | OUTPUT: |
|---|
| 100 | RETVAL |
|---|
| 101 | |
|---|
| 102 | void |
|---|
| 103 | DESTROY(self) |
|---|
| 104 | Net::Remctl self |
|---|
| 105 | CODE: |
|---|
| 106 | if (self != NULL) |
|---|
| 107 | remctl_close(self); |
|---|
| 108 | |
|---|
| 109 | void |
|---|
| 110 | remctl_open(self, host, ...) |
|---|
| 111 | Net::Remctl self |
|---|
| 112 | const char *host |
|---|
| 113 | PROTOTYPE: DISABLE |
|---|
| 114 | PREINIT: |
|---|
| 115 | size_t count = items - 2; |
|---|
| 116 | unsigned short port = 0; |
|---|
| 117 | const char *principal = NULL; |
|---|
| 118 | PPCODE: |
|---|
| 119 | if (count > 2) |
|---|
| 120 | croak("Too many arguments to Net::Remctl::open"); |
|---|
| 121 | if (count >= 1) |
|---|
| 122 | port = SvUV(ST(2)); |
|---|
| 123 | if (count >= 2 && ST(3) != &PL_sv_undef) { |
|---|
| 124 | principal = SvPV_nolen(ST(3)); |
|---|
| 125 | if (*principal == '\0') |
|---|
| 126 | principal = NULL; |
|---|
| 127 | } |
|---|
| 128 | if (remctl_open(self, host, port, principal)) |
|---|
| 129 | XSRETURN_YES; |
|---|
| 130 | else |
|---|
| 131 | XSRETURN_UNDEF; |
|---|
| 132 | |
|---|
| 133 | void |
|---|
| 134 | remctl_command(self, ...) |
|---|
| 135 | Net::Remctl self |
|---|
| 136 | PREINIT: |
|---|
| 137 | struct iovec *args; |
|---|
| 138 | size_t count = items - 1; |
|---|
| 139 | size_t i; |
|---|
| 140 | int status; |
|---|
| 141 | PPCODE: |
|---|
| 142 | if (count == 0) |
|---|
| 143 | croak("Too few arguments to Net::Remctl::command"); |
|---|
| 144 | args = malloc(sizeof(struct iovec) * count); |
|---|
| 145 | if (args == NULL) |
|---|
| 146 | croak("Error allocating memory in Net::Remctl::command: %s", |
|---|
| 147 | strerror(errno)); |
|---|
| 148 | for (i = 1; i <= count; i++) |
|---|
| 149 | args[i - 1].iov_base = SvPV(ST(i), args[i - 1].iov_len); |
|---|
| 150 | status = remctl_commandv(self, args, count); |
|---|
| 151 | free(args); |
|---|
| 152 | if (status) |
|---|
| 153 | XSRETURN_YES; |
|---|
| 154 | else |
|---|
| 155 | XSRETURN_UNDEF; |
|---|
| 156 | |
|---|
| 157 | Net::Remctl::Output |
|---|
| 158 | remctl_output(self) |
|---|
| 159 | Net::Remctl self |
|---|
| 160 | |
|---|
| 161 | const char * |
|---|
| 162 | remctl_error(self) |
|---|
| 163 | Net::Remctl self |
|---|
| 164 | |
|---|
| 165 | MODULE = Net::Remctl PACKAGE = Net::Remctl::Result |
|---|
| 166 | |
|---|
| 167 | void |
|---|
| 168 | DESTROY(self) |
|---|
| 169 | Net::Remctl::Result self |
|---|
| 170 | CODE: |
|---|
| 171 | remctl_result_free(self); |
|---|
| 172 | |
|---|
| 173 | char * |
|---|
| 174 | error(self) |
|---|
| 175 | Net::Remctl::Result self |
|---|
| 176 | CODE: |
|---|
| 177 | RETVAL = self->error; |
|---|
| 178 | OUTPUT: |
|---|
| 179 | RETVAL |
|---|
| 180 | |
|---|
| 181 | SV * |
|---|
| 182 | stdout(self) |
|---|
| 183 | Net::Remctl::Result self |
|---|
| 184 | CODE: |
|---|
| 185 | if (self->stdout_buf == NULL) |
|---|
| 186 | XSRETURN_UNDEF; |
|---|
| 187 | else |
|---|
| 188 | RETVAL = newSVpvn(self->stdout_buf, self->stdout_len); |
|---|
| 189 | OUTPUT: |
|---|
| 190 | RETVAL |
|---|
| 191 | |
|---|
| 192 | SV * |
|---|
| 193 | stderr(self) |
|---|
| 194 | Net::Remctl::Result self |
|---|
| 195 | CODE: |
|---|
| 196 | if (self->stderr_buf == NULL) |
|---|
| 197 | XSRETURN_UNDEF; |
|---|
| 198 | else |
|---|
| 199 | RETVAL = newSVpvn(self->stderr_buf, self->stderr_len); |
|---|
| 200 | OUTPUT: |
|---|
| 201 | RETVAL |
|---|
| 202 | |
|---|
| 203 | int |
|---|
| 204 | status(self) |
|---|
| 205 | Net::Remctl::Result self |
|---|
| 206 | CODE: |
|---|
| 207 | RETVAL = self->status; |
|---|
| 208 | OUTPUT: |
|---|
| 209 | RETVAL |
|---|
| 210 | |
|---|
| 211 | MODULE = Net::Remctl PACKAGE = Net::Remctl::Output |
|---|
| 212 | |
|---|
| 213 | const char * |
|---|
| 214 | type(self) |
|---|
| 215 | Net::Remctl::Output self |
|---|
| 216 | PREINIT: |
|---|
| 217 | size_t i; |
|---|
| 218 | CODE: |
|---|
| 219 | RETVAL = NULL; |
|---|
| 220 | for (i = 0; OUTPUT_TYPE[i].name != NULL; i++) |
|---|
| 221 | if (OUTPUT_TYPE[i].type == self->type) { |
|---|
| 222 | RETVAL = OUTPUT_TYPE[self->type].name; |
|---|
| 223 | break; |
|---|
| 224 | } |
|---|
| 225 | OUTPUT: |
|---|
| 226 | RETVAL |
|---|
| 227 | |
|---|
| 228 | SV * |
|---|
| 229 | data(self) |
|---|
| 230 | Net::Remctl::Output self |
|---|
| 231 | CODE: |
|---|
| 232 | if (self->data == NULL) |
|---|
| 233 | XSRETURN_UNDEF; |
|---|
| 234 | else |
|---|
| 235 | RETVAL = newSVpvn(self->data, self->length); |
|---|
| 236 | OUTPUT: |
|---|
| 237 | RETVAL |
|---|
| 238 | |
|---|
| 239 | size_t |
|---|
| 240 | length(self) |
|---|
| 241 | Net::Remctl::Output self |
|---|
| 242 | CODE: |
|---|
| 243 | RETVAL = self->length; |
|---|
| 244 | OUTPUT: |
|---|
| 245 | RETVAL |
|---|
| 246 | |
|---|
| 247 | int |
|---|
| 248 | stream(self) |
|---|
| 249 | Net::Remctl::Output self |
|---|
| 250 | CODE: |
|---|
| 251 | RETVAL = self->stream; |
|---|
| 252 | OUTPUT: |
|---|
| 253 | RETVAL |
|---|
| 254 | |
|---|
| 255 | int |
|---|
| 256 | status(self) |
|---|
| 257 | Net::Remctl::Output self |
|---|
| 258 | CODE: |
|---|
| 259 | RETVAL = self->status; |
|---|
| 260 | OUTPUT: |
|---|
| 261 | RETVAL |
|---|
| 262 | |
|---|
| 263 | int |
|---|
| 264 | error(self) |
|---|
| 265 | Net::Remctl::Output self |
|---|
| 266 | CODE: |
|---|
| 267 | RETVAL = self->error; |
|---|
| 268 | OUTPUT: |
|---|
| 269 | RETVAL |
|---|